{"record":{"id":"8016152d658ccd94","repo":"google/tsunami-security-scanner","slug":"illegal-header-value-s","errorCode":null,"errorMessage":"Illegal header value %s.","messagePattern":"Illegal header value (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"plugin_server/py/common/net/http/http_headers.py","lineNumber":104,"sourceCode":"\n    Raises:\n      ValueError: If name or value is None. If header name or value pair does\n      not comply with standards.\n    \"\"\"\n    if name is None:\n      raise ValueError('Name cannot be None.')\n    if value is None:\n      raise ValueError('Value cannot be None.')\n    if canonicalize:\n      name = self._canonicalize_header_name(name, value)\n    self.http_headers.raw_headers[name].append(value)\n    return self\n\n  def _canonicalize_header_name(self, name, value) -> str:\n    if not self._is_legal_header_name(name):\n      raise ValueError('Illegal header name %s.' % name)\n    if not self._is_legal_header_value(value):\n      raise ValueError('Illegal header value %s.' % value)\n    return _canonicalize(name)\n\n  def _is_legal_header_name(self, name: str) -> bool:\n    return bool(re.fullmatch(self.HEADER_NAME_MATCHER, name))\n\n  def _is_legal_header_value(self, value: str) -> bool:\n    return bool(re.fullmatch(self.HEADER_VALUE_MATCHER, value))\n\n\ndef _canonicalize(header_name: str) -> str:\n  \"\"\"Normalize header field name.\n\n  Args:\n    header_name: An HTTP header field name.\n\n  Returns:\n    An HttpHeaderField value or the header_name in lowercase.\n  \"\"\"","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/google/tsunami-security-scanner/blob/363ba87b3543f8ae8e4304d3416818f03da7f262/plugin_server/py/common/net/http/http_headers.py#L86-L122","documentation":"_canonicalize_header_name also validates the header value against _is_legal_header_value (analogous regex). Values containing illegal characters (e.g. newlines, control characters) raise ValueError('Illegal header value ...') to prevent header injection and malformed requests.","triggerScenarios":"add_header('X-Foo', 'v1\\nv2: injected') (CR/LF injection), a value with NUL or other control bytes, or a value read from a file/network that contains trailing control characters.","commonSituations":"Reflecting untrusted input into header values; reading tokens from files without stripping whitespace/newlines; template substitution injecting multi-line content into a header.","solutions":["Inspect the value for control characters (repr() reveals \\n, \\r, \\x00) and strip or reject them","Collapse multi-line content: value.replace('\\n', ' ').replace('\\r', ' ') or split into separate headers","Never interpolate raw user input into header values without sanitization","Encode/quote the value if the header semantics allow it (e.g. base64 for binary data)"],"exampleFix":"// before\nbuilder.add_header('X-Note', user_comment)  # may contain newlines\n// after\nbuilder.add_header('X-Note', user_comment.replace('\\r', '').replace('\\n', ' '))","handlingStrategy":"validation","validationCode":"def is_safe_header_value(value):\n    return isinstance(value, str) and not any(c in value for c in '\\r\\n\\x00')","typeGuard":null,"tryCatchPattern":"try:\n    builder.add_header(name, value)\nexcept ValueError:\n    builder.add_header(name, sanitize(value))","preventionTips":["Strip CR/LF from any externally sourced value before it becomes a header","Use repr() when debugging header values to reveal hidden control characters","Treat user input in headers as hostile; sanitize or encode it"],"tags":["python","http","headers","header-injection","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"363ba87b3543f8ae8e4304d3416818f03da7f262","analyzedAt":"2026-09-13T01:50:53.990Z","contentChangedAt":"2026-09-13T01:50:53.990Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}