{"record":{"id":"92eb37115013c2aa","repo":"symfony/http-foundation","slug":"invalid-uri-host-is-malformed","errorCode":null,"errorMessage":"Invalid URI: Host is malformed.","messagePattern":"Invalid URI: Host is malformed\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"Request.php","lineNumber":406,"sourceCode":"        ], $server);\n\n        $server['PATH_INFO'] = '';\n        $server['REQUEST_METHOD'] = strtoupper($method);\n\n        if (($i = strcspn($uri, ':/?#')) && ':' === ($uri[$i] ?? null) && (strspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-.') !== $i || strcspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'))) {\n            throw new BadRequestException('Invalid URI: Scheme is malformed.');\n        }\n        if (false === $components = parse_url(\\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#')) {\n            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']) {","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/symfony/http-foundation/blob/5aea19cd678fa4140f6108406f1096de5e9ed6e4/Request.php#L388-L424","documentation":"Request::create() validates the host component extracted from the URI with self::isHostValid(). If a non-empty host fails that check (disallowed characters or malformed IPv6 literal), the factory refuses to build the Request and throws BadRequestException ('Invalid URI: Host is malformed.'), which maps to an HTTP 400. This blocks host-header injection and DNS-rebinding style URLs at construction time.","triggerScenarios":"Calling Request::create('http://<bad-host>/...') where the host contains characters outside the allowed set (letters, digits, '-', '.', and bracketed IPv6 per isHostValid), e.g. 'http://host_name/' with underscore, 'http://[not-ipv6]/', or hosts with spaces/commas. parse_url() extracted a 'host' key but isHostValid() rejected it at Request.php:405-406.","commonSituations":"Building requests from user-provided callback/webhook URLs; misconfigured base URLs in config (typo, underscore in hostname); test suites exercising invalid-host handling; SSRF filters that should reject bad hosts before reaching the framework.","solutions":["Fix the URI so its host is a valid registered name (RFC 1123: letters, digits, hyphens, dots) or a bracketed IPv6 literal, e.g. 'http://my-host.example.com/'.","Validate the host before calling: parse_url($uri, PHP_URL_HOST) and run the same kind of check (or filter_var($host, FILTER_VALIDATE_DOMAIN)).","If the value comes from configuration, correct the base-url/host config entry (underscores and spaces are not valid in hostnames).","For untrusted input, catch BadRequestException from Request::create() and reject the request with a 400."],"exampleFix":"// before\n$request = Request::create('http://my_host.example.com/path'); // underscore: invalid\n// after\n$host = parse_url($uri, PHP_URL_HOST);\nif (!preg_match('/^(\\[?[a-f0-9:.]+\\]?)$|^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i', (string) $host)) {\n    throw new \\InvalidArgumentException('Invalid host in URI');\n}\n$request = Request::create($uri);","handlingStrategy":"validation","validationCode":"function hasValidHost(string $uri): bool\n{\n    $host = parse_url($uri, PHP_URL_HOST);\n    if (null === $host || false === $host || '' === $host) {\n        return true; // no host component: this specific check does not apply\n    }\n    if (preg_match('/^\\[.+\\]$/', $host)) {\n        return false !== filter_var(trim($host, '[]'), FILTER_VALIDATE_IP);\n    }\n\n    return (bool) preg_match('/^(?!-)[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*\\.?$/', $host);\n}\nif (!hasValidHost($uri)) {\n    throw new \\InvalidArgumentException('Invalid host in URI');\n}","typeGuard":"function isWellFormedUrl(string $uri): bool\n{\n    $c = parse_url($uri);\n\n    return false !== $c && (!isset($c['host']) || '' !== $c['host']);\n}","tryCatchPattern":"try {\n    $request = Request::create($uri);\n} catch (BadRequestException $e) {\n    if (str_contains($e->getMessage(), 'Host is malformed')) {\n        return new Response('Unacceptable host in URL.', 400);\n    }\n\n    throw $e;\n}","preventionTips":["Keep hostnames in config RFC-1123 compliant (no underscores, spaces, or commas)","Use filter_var($host, FILTER_VALIDATE_DOMAIN) on user-supplied hosts before building requests","For IPv6 targets always wrap the address in square brackets: http://[::1]/","Add tests for invalid hosts (underscore, bad IPv6 literal) around every code path that accepts external URLs"],"tags":["http","uri-validation","request","hostname"],"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"}