Secure HTTP Header Mutations in JavaScript Headers
The Fetch API’s Headers interface provides a built-in,
secure mechanism for reading, modifying, and validating HTTP headers in
modern JavaScript. This article explains how the Headers
object safeguards network operations by employing internal header
guards, blocking forbidden header names, enforcing strict syntactic
validation to prevent injection attacks, and normalizing header keys
during mutation operations.
Header Guards
The primary security mechanism inside a Headers instance
is an internal property known as the guard. The guard
determines whether headers can be modified, appended, or deleted based
on the context in which the object is used.
JavaScript defines five guard states:
none: Default state for standalonenew Headers()instances. All valid mutations (append,set,delete) are permitted.request: Applied to theheadersof aRequestobject. Mutations are permitted except for forbidden request header names.request-no-cors: Applied to requests created withmode: 'no-cors'. Mutations are restricted strictly to CORS-safelisted request headers (Accept,Accept-Language,Content-Language, orContent-Typewith specific MIME types).response: Applied to theheadersof aResponseobject. Mutations that alter forbidden response header names (such asSet-CookieorSet-Cookie2) are blocked.immutable: Applied to instances such as cached responses or responses fromfetch()calls. Any attempt to callset(),append(), ordelete()throws aTypeError.
// Example: Attempting to mutate an immutable response header
fetch('https://api.example.com/data')
.then(response => {
// Throws TypeError: Failed to execute 'set' on 'Headers': Headers are immutable
response.headers.set('X-Custom-Header', 'value');
});Forbidden Header Restrictions
To prevent malicious scripts from spoofing identity, bypassing
security policies, or hijacking sessions, the Headers
object disallows programmatic modification of specific headers.
Forbidden Request Headers
When the guard is set to request, browsers block
modifications to headers controlled exclusively by the user agent: *
Accept-Charset, Accept-Encoding,
Access-Control-Request-Headers,
Access-Control-Request-Method * Connection,
Content-Length, Cookie, Cookie2,
Date, DNT * Host,
Keep-Alive, Origin, Referer,
TE, Trailer, Transfer-Encoding,
Upgrade, Via * Any header prefixed with
Proxy- or Sec-
Attempting to mutate these headers does not throw an error in standard environments; instead, the modification is silently ignored, preventing unintended execution crashes while maintaining security.
Preventing HTTP Header Injection
HTTP Header Injection (or HTTP Response Splitting) occurs when
untrusted input containing carriage return (\r or
0x0D) and newline (\n or 0x0A)
characters is written into headers, allowing attackers to inject
arbitrary headers or split HTTP messages.
The Headers interface prevents this by strictly
enforcing HTTP token and byte validation rules in compliance with the
HTTP/1.1 and HTTP/2 specifications (RFC 9110):
- Name Validation: Header names must match the
tokenABNF production (alphanumeric and specific standard symbols only). Whitespace, colons, control characters, or non-ASCII characters immediately throw aTypeError. - Value Validation: Header values are checked for
prohibited control characters (
\0,\r,\n). If a newline or invalid byte sequence is passed toappend()orset(), the browser throws aTypeError.
const headers = new Headers();
// Throws TypeError: Invalid character in header field name
headers.set('Bad:Name', 'value');
// Throws TypeError: String contains invalid characters (prevents CRLF injection)
headers.set('X-Custom', 'valid\r\nInjected-Header: evil');Case-Insensitive Normalization and Merging
The Headers interface ensures consistency across
operations by automatically normalizing all header names to lowercase
byte-sequences before executing mutations:
- Case-Insensitive Deduplication: Calling
set('Content-Type', 'text/json')will overwrite existing entries forcontent-type,CONTENT-TYPE, orContent-Type, eliminating duplicate variations that could lead to header-precedence vulnerabilities. - Controlled Appending: Using
append()safely concatenates values with a comma and a space (,) where multi-value headers are RFC-compliant, ensuring that payloads are structured consistently without malformed raw strings.