{"record":{"id":"b89494c0d9bf600f","repo":"psf/requests","slug":"invalid-leading-whitespace-reserved-character-s","errorCode":null,"errorMessage":"Invalid leading whitespace, reserved character(s), or return character(s) in header {header_kind}: {header_part!r}","messagePattern":"Invalid leading whitespace, reserved character\\(s\\), or return character\\(s\\) in header (.+?): (.+?)","errorType":"exception","errorClass":"InvalidHeader","httpStatus":null,"severity":"error","filePath":"src/requests/utils.py","lineNumber":1116,"sourceCode":"def _validate_header_part(\n    header: tuple[str | bytes, str | bytes],\n    header_part: str | bytes,\n    header_validator_index: int,\n) -> None:\n    if isinstance(header_part, str):\n        validator = _HEADER_VALIDATORS_STR[header_validator_index]\n    elif isinstance(header_part, bytes):\n        # runtime guard for non-str/bytes input\n        validator = _HEADER_VALIDATORS_BYTE[header_validator_index]\n    else:\n        raise InvalidHeader(\n            f\"Header part ({header_part!r}) from {header} \"\n            f\"must be of type str or bytes, not {type(header_part)}\"\n        )\n\n    if not validator.match(header_part):  # type: ignore[arg-type]\n        header_kind = \"name\" if header_validator_index == 0 else \"value\"\n        raise InvalidHeader(\n            f\"Invalid leading whitespace, reserved character(s), or return \"\n            f\"character(s) in header {header_kind}: {header_part!r}\"\n        )\n\n\ndef urldefragauth(url: str) -> str:\n    \"\"\"\n    Given a url remove the fragment and the authentication part.\n\n    :rtype: str\n    \"\"\"\n    scheme, netloc, path, params, query, _fragment = urlparse(url)\n\n    # see func:`prepend_scheme_if_needed`\n    if not netloc:\n        netloc, path = path, netloc\n\n    netloc = netloc.rsplit(\"@\", 1)[-1]","sourceCodeStart":1098,"sourceCodeEnd":1134,"githubUrl":"https://github.com/psf/requests/blob/8068356288978c4f54661ae6f95afe0e0831885e/src/requests/utils.py#L1098-L1134","documentation":"Raised by _validate_header_part() when a header name or value contains characters that fail the validator regex: leading whitespace (for values), colons or whitespace (for names), or CR/LF characters anywhere. This is primarily a security guard against HTTP header injection (CRLF injection) attacks.","triggerScenarios":"Header value containing '\\r\\n' or '\\n' (newline injection); header name with a colon; header value with leading space; header value containing raw return characters from user input or multi-line strings.","commonSituations":"User-supplied data placed into headers without sanitization (security vulnerability); copy-pasting multi-line strings into header values; building headers from log lines or file contents that contain newlines; deliberate header injection attempts from malicious input.","solutions":["Strip CR/LF and leading whitespace from all header values before passing to requests: v.replace('\\r', '').replace('\\n', '').strip().","Sanitize user input before placing it in headers: reject or escape any control characters.","Use a header sanitization function for any data sourced from external input."],"exampleFix":"# before\nrequests.get(url, headers={'X-User': user_input})  # user_input = 'alice\\r\\nX-Admin: true'\n\n# after — sanitize\ndef safe_header(v):\n    return str(v).replace('\\r', '').replace('\\n', '').strip()\n\nheaders = {k: safe_header(v) for k, v in raw_headers.items()}\nrequests.get(url, headers=headers)","handlingStrategy":"validation","validationCode":"import re\ndef sanitize_header(value):\n    v = str(value).replace('\\r', '').replace('\\n', '').strip()\n    if re.search(r'[\\x00-\\x1f]', v):\n        raise ValueError(f'Header contains control characters: {v!r}')\n    return v\n\nclean_headers = {k: sanitize_header(v) for k, v in headers.items()}\nresp = requests.get(url, headers=clean_headers)","typeGuard":"import re\ndef is_safe_header_value(v) -> bool:\n    if not isinstance(v, (str, bytes)):\n        return False\n    s = v if isinstance(v, str) else v.decode('ascii', errors='replace')\n    return not re.search(r'[\\r\\n]', s) and (not s or not s[0].isspace())","tryCatchPattern":"try:\n    resp = requests.get(url, headers=headers)\nexcept requests.exceptions.InvalidHeader as e:\n    logger.error(f'Header validation failed: {e}')\n    clean = {k: str(v).replace('\\r', '').replace('\\n', '').strip()\n             for k, v in headers.items()}\n    resp = requests.get(url, headers=clean)","preventionTips":["Never place raw user input into HTTP headers without sanitizing CR/LF characters.","Strip whitespace and control characters from all header values before passing to requests.","Treat header construction from external data as a security boundary (header injection risk).","Validate header names don't contain colons or whitespace."],"tags":["invalid-header","header-injection","security","crlf","headers","input-validation"],"backgroundTag":null,"analyzedSha":"8068356288978c4f54661ae6f95afe0e0831885e","analyzedAt":"2026-08-11T20:11:09.238Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}