{"record":{"id":"86653833895277a0","repo":"symfony/http-foundation","slug":"invalid-uri-a-uri-must-not-start-nor-end-with-ascii-control","errorCode":null,"errorMessage":"Invalid URI: A URI must not start nor end with ASCII control characters or spaces.","messagePattern":"Invalid URI: A URI must not start nor end with ASCII control characters or spaces\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"Request.php","lineNumber":415,"sourceCode":"            throw new BadRequestException('Invalid URI.');\n        }\n\n        $part = ($components['user'] ?? '').':'.($components['pass'] ?? '');\n\n        if (':' !== $part && \\strlen($part) !== strcspn($part, '[]')) {\n            throw new BadRequestException('Invalid URI: Userinfo is malformed.');\n        }\n        if (($part = $components['host'] ?? '') && !self::isHostValid($part)) {\n            throw new BadRequestException('Invalid URI: Host is malformed.');\n        }\n        if (false !== ($i = strpos($uri, '\\\\')) && $i < strcspn($uri, '?#')) {\n            throw new BadRequestException('Invalid URI: A URI cannot contain a backslash.');\n        }\n        if (\\strlen($uri) !== strcspn($uri, \"\\r\\n\\t\")) {\n            throw new BadRequestException('Invalid URI: A URI cannot contain CR/LF/TAB characters.');\n        }\n        if ('' !== $uri && (\\ord($uri[0]) <= 32 || \\ord($uri[-1]) <= 32)) {\n            throw new BadRequestException('Invalid URI: A URI must not start nor end with ASCII control characters or spaces.');\n        }\n\n        if (isset($components['host'])) {\n            $server['SERVER_NAME'] = $components['host'];\n            $server['HTTP_HOST'] = $components['host'];\n        }\n\n        if (isset($components['scheme'])) {\n            if ('https' === $components['scheme']) {\n                $server['HTTPS'] = 'on';\n                $server['SERVER_PORT'] = 443;\n            } else {\n                unset($server['HTTPS']);\n                $server['SERVER_PORT'] = 80;\n            }\n        }\n\n        if (isset($components['port'])) {","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/symfony/http-foundation/blob/5aea19cd678fa4140f6108406f1096de5e9ed6e4/Request.php#L397-L433","documentation":"Request::create() requires the URI to neither start nor end with an ASCII character <= 32 (control characters or spaces). Leading/trailing whitespace or control bytes usually indicate unsanitized input and can be used to smuggle alternate request lines; the library throws BadRequestException ('Invalid URI: A URI must not start nor end with ASCII control characters or spaces.') producing HTTP 400.","triggerScenarios":"Calling Request::create() with a URI that begins or ends with a space, NUL, or other byte with ord() <= 32, e.g. ' http://host/' or \"http://host/\\0\" — checked at Request.php:413-415 via ord($uri[0]) <= 32 || ord($uri[-1]) <= 32 on a non-empty URI. Empty-string URIs are exempt from this specific check.","commonSituations":"URIs pasted with surrounding whitespace from logs, emails, or CLI arguments; values read from files/DB with trailing newline (handled by the previous check) or trailing spaces; fuzzing/security tests prepending NUL bytes or spaces to bypass filters.","solutions":["Trim the URI before passing it: Request::create(trim($uri)).","Validate up front: reject if $uri === trim($uri, \" \\t\\n\\r\\0\\x0B\") is false, or if ord($uri[0]) <= 32.","Fix the source that appends/prepends whitespace (e.g. rtrim() file/DB values, remove quotes from CLI input).","Catch BadRequestException when the URI is untrusted and return a 400 to the client."],"exampleFix":"// before\n$request = Request::create(' http://example.com/path ');\n// after\n$uri = trim(' http://example.com/path ');\nif ('' !== $uri && (ord($uri[0]) <= 32 || ord($uri[-1]) <= 32)) {\n    throw new \\InvalidArgumentException('URI has leading/trailing control chars');\n}\n$request = Request::create($uri);","handlingStrategy":"validation","validationCode":"function hasCleanEnds(string $uri): bool\n{\n    return '' === $uri || (ord($uri[0]) > 32 && ord($uri[-1]) > 32);\n}\n$uri = trim($uri);\nif (!hasCleanEnds($uri)) {\n    throw new \\InvalidArgumentException('URI has leading/trailing control chars');\n}\n$request = Request::create($uri);","typeGuard":"function isTrimmedUri(mixed $uri): bool\n{\n    return \\is_string($uri) && $uri === trim($uri, \" \\t\\n\\r\\0\\x0B\") && '' !== $uri;\n}","tryCatchPattern":"try {\n    $request = Request::create($uri);\n} catch (BadRequestException $e) {\n    if (str_contains($e->getMessage(), 'control characters or spaces')) {\n        $request = Request::create(trim($uri));\n    } else {\n        throw $e;\n    }\n}","preventionTips":["trim() every URI coming from logs, CLI args, emails, or form fields before use","Store and transport URLs without surrounding whitespace; fix producers, not just consumers","Check for NUL bytes (ord <= 32) which trim() also removes — belt and suspenders with an explicit check","Add a normalization helper (trim + control-char scan) applied at the single point where external URIs enter the system"],"tags":["http","uri-validation","request","input-sanitization"],"backgroundTag":"invalid-url-format","analyzedSha":"5aea19cd678fa4140f6108406f1096de5e9ed6e4","analyzedAt":"2026-09-13T01:52:22.855Z","contentChangedAt":"2026-09-13T01:52:22.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}