Exposure of Private Personal Information to an Unauthorized Actor in follow-redirects/follow-redirects
Description
follow-redirects is vulnerable to Exposure of Private Personal Information to an Unauthorized Actor
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
follow-redirects leaks cookies across cross-domain redirects, potentially exposing sensitive data to unauthorized hosts.
## Vulnerability follow-redirects versions prior to the commit 8b347cb (fixed in unspecified release) improperly retain cookies when following HTTP redirects to a different domain. The module is a drop-in replacement for Node.js http and https that automatically follows redirects. Under normal operation, the Authorization header was already stripped on cross-domain redirects, but the Cookie header was not. This oversight can expose private personal information to an unauthorized actor [1][3].
Exploitation
An attacker does not need special network position; they can host a malicious server that issues an HTTP redirect (e.g., 301, 302, 307) to a different domain under their control. When a client using an affected version of follow-redirects makes a request that includes cookies (e.g., via a Cookie header set by the application), the module will forward those cookies to the attacker's domain. No authentication or user interaction beyond making the initial request is required [3][4].
Impact
Successful exploitation allows an attacker to obtain cookies intended for the original domain. These cookies may contain session tokens or other sensitive personal information, leading to unauthorized access, session hijacking, or exposure of private data. The impact is limited to cookie disclosure; depending on the application’s use of cookies, the attacker may impersonate the victim [2][4].
Mitigation
The fix is implemented in commit 8b347cb on the follow-redirects repository, where the removeMatchingHeaders call now also matches the cookie header (in addition to authorization). Users should update to the patched version (if a release is published) or apply the commit directly. No workaround is available other than manually stripping the Cookie header on redirects. Siemens also references this CVE in their advisory ssa-637483 [2][3][4].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
follow-redirectsnpm | < 1.14.7 | 1.14.7 |
Affected products
93- ghsa-coords92 versionspkg:npm/follow-redirectspkg:rpm/opensuse/bind&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/dracut-saltboot&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/dracut-saltboot&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/golang-github-lusitaniae-apache_exporter&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/grafana&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/grafana&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/prometheus-postgres_exporter&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/spacecmd&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/spacecmd&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/wire&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/wire&distro=openSUSE%20Leap%2015.5pkg:rpm/suse/ansible&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/bind&distro=SUSE%20Enterprise%20Storage%207pkg:rpm/suse/bind&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP1-LTSSpkg:rpm/suse/bind&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP2-LTSSpkg:rpm/suse/bind&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP1-LTSSpkg:rpm/suse/bind&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP2-LTSSpkg:rpm/suse/bind&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP1pkg:rpm/suse/bind&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP2pkg:rpm/suse/bind&distro=SUSE%20Manager%20Client%20Tools%20for%20SLE%20Micro%205pkg:rpm/suse/dracut-saltboot&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/dracut-saltboot&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/dracut-saltboot&distro=SUSE%20Manager%20Client%20Tools%20Beta%20for%20SLE%20Micro%205pkg:rpm/suse/dracut-saltboot&distro=SUSE%20Manager%20Client%20Tools%20for%20SLE%20Micro%205pkg:rpm/suse/golang-github-boynux-squid_exporter&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/golang-github-boynux-squid_exporter&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/golang-github-lusitaniae-apache_exporter&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/golang-github-lusitaniae-apache_exporter&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/golang-github-lusitaniae-apache_exporter&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/golang-github-lusitaniae-apache_exporter&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/golang-github-lusitaniae-apache_exporter&distro=SUSE%20Manager%20Proxy%20Module%204.3pkg:rpm/suse/golang-github-lusitaniae-apache_exporter&distro=SUSE%20Manager%20Server%20Module%204.3pkg:rpm/suse/golang-github-prometheus-alertmanager&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/golang-github-prometheus-alertmanager&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/golang-github-prometheus-node_exporter&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/golang-github-prometheus-prometheus&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/golang-github-prometheus-prometheus&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/golang-github-prometheus-prometheus&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/golang-github-prometheus-prometheus&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/golang-github-prometheus-promu&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/golang-github-QubitProducts-exporter_exporter&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/golang-github-QubitProducts-exporter_exporter&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/golang-github-QubitProducts-exporter_exporter&distro=SUSE%20Manager%20Client%20Tools%20Beta%20for%20SLE%20Micro%205pkg:rpm/suse/grafana&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Package%20Hub%2015%20SP4pkg:rpm/suse/grafana&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Package%20Hub%2015%20SP5pkg:rpm/suse/grafana&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/grafana&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/grafana&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/grafana&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/kiwi-desc-saltboot&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/mgr-daemon&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/mgr-daemon&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/mgr-push&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/mgr-push&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/prometheus-blackbox_exporter&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/prometheus-blackbox_exporter&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/prometheus-blackbox_exporter&distro=SUSE%20Manager%20Client%20Tools%20Beta%20for%20SLE%20Micro%205pkg:rpm/suse/prometheus-postgres_exporter&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/prometheus-postgres_exporter&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/prometheus-postgres_exporter&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/prometheus-postgres_exporter&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/python-hwdata&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/python-hwdata&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/python-pyvmomi&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/rhnlib&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/rhnlib&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/spacecmd&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/spacecmd&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/spacecmd&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/spacecmd&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/spacewalk-client-tools&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/spacewalk-client-tools&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/spacewalk-client-tools&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/supportutils-plugin-salt&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/supportutils-plugin-salt&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/supportutils-plugin-susemanager-client&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/supportutils-plugin-susemanager-client&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/system-user-grafana&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/system-user-prometheus&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/uyuni-common-libs&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/uyuni-common-libs&distro=SUSE%20Manager%20Client%20Tools%2012-BETApkg:rpm/suse/uyuni-common-libs&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/uyuni-common-libs&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/uyuni-proxy-systemd-services&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/uyuni-proxy-systemd-services&distro=SUSE%20Manager%20Client%20Tools%2015-BETApkg:rpm/suse/uyuni-proxy-systemd-services&distro=SUSE%20Manager%20Client%20Tools%20Beta%20for%20SLE%20Micro%205pkg:rpm/suse/uyuni-proxy-systemd-services&distro=SUSE%20Manager%20Client%20Tools%20for%20SLE%20Micro%205pkg:rpm/suse/zypp-plugin-spacewalk&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/zypp-plugin-spacewalk&distro=SUSE%20Manager%20Client%20Tools%2015pkg:rpm/suse/zypp-plugin-spacewalk&distro=SUSE%20Manager%20Proxy%20Module%204.2pkg:rpm/suse/zypp-plugin-spacewalk&distro=SUSE%20Manager%20Proxy%20Module%204.3
< 1.14.7+ 91 more
- (no CPE)range: < 1.14.7
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 0.1.1681904360.84ef141-150000.1.50.1
- (no CPE)range: < 0.1.1681904360.84ef141-150000.1.50.1
- (no CPE)range: < 1.0.0-150000.1.20.1
- (no CPE)range: < 9.5.1-150200.3.41.3
- (no CPE)range: < 9.5.8-150200.3.53.2
- (no CPE)range: < 0.10.1-150000.1.17.1
- (no CPE)range: < 4.3.21-150000.3.98.1
- (no CPE)range: < 4.3.21-150000.3.98.1
- (no CPE)range: < 0.5.0-150000.1.12.3
- (no CPE)range: < 0.5.0-150000.1.12.3
- (no CPE)range: < 2.9.27-159000.3.9.1
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 9.16.6-150000.12.65.1
- (no CPE)range: < 0.1.1681904360.84ef141-150000.1.50.1
- (no CPE)range: < 0.1.1681904360.84ef141-159000.3.30.1
- (no CPE)range: < 0.1.1681904360.84ef141-159000.3.30.1
- (no CPE)range: < 0.1.1681904360.84ef141-150000.1.50.1
- (no CPE)range: < 1.6-4.9.2
- (no CPE)range: < 1.6-159000.4.9.1
- (no CPE)range: < 1.0.0-1.21.2
- (no CPE)range: < 1.0.0-4.12.4
- (no CPE)range: < 1.0.0-150000.1.20.1
- (no CPE)range: < 1.0.0-159000.4.12.1
- (no CPE)range: < 1.0.0-150000.1.20.1
- (no CPE)range: < 1.0.0-150000.1.20.1
- (no CPE)range: < 0.26.0-1.24.2
- (no CPE)range: < 0.26.0-4.12.4
- (no CPE)range: < 1.5.0-4.15.4
- (no CPE)range: < 2.45.0-1.50.2
- (no CPE)range: < 2.45.0-4.33.3
- (no CPE)range: < 2.45.0-150000.3.53.1
- (no CPE)range: < 2.45.0-159000.6.33.1
- (no CPE)range: < 0.14.0-4.12.2
- (no CPE)range: < 0.4.0-4.6.2
- (no CPE)range: < 0.4.0-159000.4.6.1
- (no CPE)range: < 0.4.0-159000.4.6.1
- (no CPE)range: < 9.5.1-150200.3.41.3
- (no CPE)range: < 9.5.8-150200.3.53.2
- (no CPE)range: < 9.5.1-1.48.1
- (no CPE)range: < 9.5.8-4.21.2
- (no CPE)range: < 9.5.1-150000.1.48.5
- (no CPE)range: < 9.5.8-159000.4.24.1
- (no CPE)range: < 0.1.1687520761.cefb248-4.15.2
- (no CPE)range: < 4.3.7-1.41.1
- (no CPE)range: < 4.3.7-150000.1.41.1
- (no CPE)range: < 5.0.1-4.21.4
- (no CPE)range: < 5.0.1-159000.4.21.1
- (no CPE)range: < 0.24.0-3.6.3
- (no CPE)range: < 0.24.0-159000.3.6.1
- (no CPE)range: < 0.24.0-159000.3.6.1
- (no CPE)range: < 0.10.1-1.17.2
- (no CPE)range: < 0.10.1-3.6.4
- (no CPE)range: < 0.10.1-150000.1.17.1
- (no CPE)range: < 0.10.1-159000.3.6.1
- (no CPE)range: < 2.3.5-15.12.2
- (no CPE)range: < 2.3.5-159000.5.13.1
- (no CPE)range: < 6.7.3-159000.3.6.1
- (no CPE)range: < 5.0.1-24.30.3
- (no CPE)range: < 5.0.1-159000.6.30.1
- (no CPE)range: < 4.3.21-38.121.1
- (no CPE)range: < 5.0.1-41.42.3
- (no CPE)range: < 4.3.21-150000.3.98.1
- (no CPE)range: < 5.0.1-159000.6.42.1
- (no CPE)range: < 4.3.18-52.95.2
- (no CPE)range: < 4.3.18-150000.3.86.2
- (no CPE)range: < 5.0.1-159000.6.48.1
- (no CPE)range: < 1.2.2-9.9.2
- (no CPE)range: < 1.2.2-159000.5.9.1
- (no CPE)range: < 5.0.1-9.15.2
- (no CPE)range: < 5.0.1-159000.6.15.1
- (no CPE)range: < 1.0.0-3.7.2
- (no CPE)range: < 1.0.0-3.7.2
- (no CPE)range: < 4.3.8-1.33.1
- (no CPE)range: < 5.0.1-3.33.3
- (no CPE)range: < 4.3.8-150000.1.33.1
- (no CPE)range: < 5.0.1-159000.3.33.1
- (no CPE)range: < 4.3.10-150000.1.15.1
- (no CPE)range: < 5.0.1-159000.3.9.1
- (no CPE)range: < 5.0.1-159000.3.9.1
- (no CPE)range: < 4.3.10-150000.1.15.1
- (no CPE)range: < 1.0.14-30.42.1
- (no CPE)range: < 1.0.14-150000.3.35.1
- (no CPE)range: < 1.0.14-150000.3.35.1
- (no CPE)range: < 1.0.14-150000.3.35.1
- follow-redirects/follow-redirects/follow-redirectsv5Range: unspecified
Patches
18b347cbcef7cDrop Cookie header across domains.
2 files changed · +175 −182
index.js+2 −2 modified@@ -392,9 +392,9 @@ RedirectableRequest.prototype._processResponse = function (response) { var redirectUrlParts = url.parse(redirectUrl); Object.assign(this._options, redirectUrlParts); - // Drop the Authorization header if redirecting to another domain + // Drop the confidential headers when redirecting to another domain if (!(redirectUrlParts.host === currentHost || isSubdomainOf(redirectUrlParts.host, currentHost))) { - removeMatchingHeaders(/^authorization$/i, this._options.headers); + removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers); } // Evaluate the beforeRedirect callback
test/test.js+173 −180 modified@@ -1319,215 +1319,208 @@ describe("follow-redirects", function () { }); }); - describe("when the client passes an Authorization header", function () { - it("ignores it when null", function () { - app.get("/a", redirectsTo(302, "http://localhost:3600/b")); - app.get("/b", function (req, res) { - res.end(JSON.stringify(req.headers)); - }); - - var opts = url.parse("http://127.0.0.1:3600/a"); - opts.headers = { - host: "localhost", - authorization: null, - }; - - return server.start(app) - .then(asPromise(function (resolve, reject) { - http.get(opts, resolve).on("error", reject); - })) - .then(asPromise(function (resolve, reject, res) { - res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); - })) - .then(function (str) { - var body = JSON.parse(str); - assert.equal(body.host, "localhost:3600"); - assert.equal(body.authorization, undefined); + [ + "Authorization", + "Cookie", + ].forEach(function (header) { + describe("when the client passes an header named " + header, function () { + it("ignores it when null", function () { + app.get("/a", redirectsTo(302, "http://localhost:3600/b")); + app.get("/b", function (req, res) { + res.end(JSON.stringify(req.headers)); }); - }); - it("keeps the header when redirected to the same host", function () { - app.get("/a", redirectsTo(302, "/b")); - app.get("/b", function (req, res) { - res.end(JSON.stringify(req.headers)); - }); + var opts = url.parse("http://127.0.0.1:3600/a"); + opts.headers = { host: "localhost" }; + opts.headers[header] = null; - var opts = url.parse("http://localhost:3600/a"); - opts.headers = { - authorization: "bearer my-token-1234", - }; + return server.start(app) + .then(asPromise(function (resolve, reject) { + http.get(opts, resolve).on("error", reject); + })) + .then(asPromise(function (resolve, reject, res) { + res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); + })) + .then(function (str) { + var body = JSON.parse(str); + assert.equal(body.host, "localhost:3600"); + assert.equal(body[header.toLowerCase()], undefined); + }); + }); - return server.start(app) - .then(asPromise(function (resolve, reject) { - http.get(opts, resolve).on("error", reject); - })) - .then(asPromise(function (resolve, reject, res) { - res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); - })) - .then(function (str) { - var body = JSON.parse(str); - assert.equal(body.host, "localhost:3600"); - assert.equal(body.authorization, "bearer my-token-1234"); + it("keeps the header when redirected to the same host", function () { + app.get("/a", redirectsTo(302, "/b")); + app.get("/b", function (req, res) { + res.end(JSON.stringify(req.headers)); }); - }); - it("keeps the header when redirected to the same host via header", function () { - app.get("/a", redirectsTo(302, "http://localhost:3600/b")); - app.get("/b", function (req, res) { - res.end(JSON.stringify(req.headers)); - }); + var opts = url.parse("http://localhost:3600/a"); + opts.headers = {}; + opts.headers[header] = "the header value"; - var opts = url.parse("http://127.0.0.1:3600/a"); - opts.headers = { - host: "localhost:3600", - authorization: "bearer my-token-1234", - }; + return server.start(app) + .then(asPromise(function (resolve, reject) { + http.get(opts, resolve).on("error", reject); + })) + .then(asPromise(function (resolve, reject, res) { + res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); + })) + .then(function (str) { + var body = JSON.parse(str); + assert.equal(body.host, "localhost:3600"); + assert.equal(body[header.toLowerCase()], "the header value"); + }); + }); - return server.start(app) - .then(asPromise(function (resolve, reject) { - http.get(opts, resolve).on("error", reject); - })) - .then(asPromise(function (resolve, reject, res) { - res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); - })) - .then(function (str) { - var body = JSON.parse(str); - assert.equal(body.host, "localhost:3600"); - assert.equal(body.authorization, "bearer my-token-1234"); + it("keeps the header when redirected to the same host via header", function () { + app.get("/a", redirectsTo(302, "http://localhost:3600/b")); + app.get("/b", function (req, res) { + res.end(JSON.stringify(req.headers)); }); - }); - it("keeps the header when redirected to the same host via header", function () { - app.get("/a", redirectsTo(302, "http://localhost:3600/b")); - app.get("/b", function (req, res) { - res.end(JSON.stringify(req.headers)); - }); + var opts = url.parse("http://127.0.0.1:3600/a"); + opts.headers = { host: "localhost:3600" }; + opts.headers[header] = "the header value"; - var opts = url.parse("http://127.0.0.1:3600/a"); - opts.headers = { - host: "localhost:3600", - authorization: "bearer my-token-1234", - }; + return server.start(app) + .then(asPromise(function (resolve, reject) { + http.get(opts, resolve).on("error", reject); + })) + .then(asPromise(function (resolve, reject, res) { + res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); + })) + .then(function (str) { + var body = JSON.parse(str); + assert.equal(body.host, "localhost:3600"); + assert.equal(body[header.toLowerCase()], "the header value"); + }); + }); - return server.start(app) - .then(asPromise(function (resolve, reject) { - http.get(opts, resolve).on("error", reject); - })) - .then(asPromise(function (resolve, reject, res) { - res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); - })) - .then(function (str) { - var body = JSON.parse(str); - assert.equal(body.host, "localhost:3600"); - assert.equal(body.authorization, "bearer my-token-1234"); + it("keeps the header when redirected to the same host via header", function () { + app.get("/a", redirectsTo(302, "http://localhost:3600/b")); + app.get("/b", function (req, res) { + res.end(JSON.stringify(req.headers)); }); - }); - it("keeps the header when redirected to a subdomain", function () { - app.get("/a", redirectsTo(302, "http://sub.localhost:3600/b")); - app.get("/b", function (req, res) { - res.end(JSON.stringify(req.headers)); - }); + var opts = url.parse("http://127.0.0.1:3600/a"); + opts.headers = { host: "localhost:3600" }; + opts.headers[header] = "the header value"; - var opts = url.parse("http://localhost:3600/a"); - opts.headers = { - authorization: "bearer my-token-1234", - }; - // Intercept the hostname, as no DNS entry is defined for it - opts.beforeRedirect = function (options) { - assert.equal(options.hostname, "sub.localhost"); - options.hostname = "localhost"; - }; + return server.start(app) + .then(asPromise(function (resolve, reject) { + http.get(opts, resolve).on("error", reject); + })) + .then(asPromise(function (resolve, reject, res) { + res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); + })) + .then(function (str) { + var body = JSON.parse(str); + assert.equal(body.host, "localhost:3600"); + assert.equal(body[header.toLowerCase()], "the header value"); + }); + }); - return server.start(app) - .then(asPromise(function (resolve, reject) { - http.get(opts, resolve).on("error", reject); - })) - .then(asPromise(function (resolve, reject, res) { - res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); - })) - .then(function (str) { - var body = JSON.parse(str); - assert.equal(body.host, "localhost:3600"); - assert.equal(body.authorization, "bearer my-token-1234"); + it("keeps the header when redirected to a subdomain", function () { + app.get("/a", redirectsTo(302, "http://sub.localhost:3600/b")); + app.get("/b", function (req, res) { + res.end(JSON.stringify(req.headers)); }); - }); - it("drops the header when redirected to a different host (same hostname and different port)", function () { - app.get("/a", redirectsTo(302, "http://localhost:3600/b")); - app.get("/b", function (req, res) { - res.end(JSON.stringify(req.headers)); - }); + var opts = url.parse("http://localhost:3600/a"); + opts.headers = {}; + opts.headers[header] = "the header value"; - var opts = url.parse("http://127.0.0.1:3600/a"); - opts.headers = { - host: "localhost", - authorization: "bearer my-token-1234", - }; + // Intercept the hostname, as no DNS entry is defined for it + opts.beforeRedirect = function (options) { + assert.equal(options.hostname, "sub.localhost"); + options.hostname = "localhost"; + }; - return server.start(app) - .then(asPromise(function (resolve, reject) { - http.get(opts, resolve).on("error", reject); - })) - .then(asPromise(function (resolve, reject, res) { - res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); - })) - .then(function (str) { - var body = JSON.parse(str); - assert.equal(body.host, "localhost:3600"); - assert.equal(body.authorization, undefined); + return server.start(app) + .then(asPromise(function (resolve, reject) { + http.get(opts, resolve).on("error", reject); + })) + .then(asPromise(function (resolve, reject, res) { + res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); + })) + .then(function (str) { + var body = JSON.parse(str); + assert.equal(body.host, "localhost:3600"); + assert.equal(body[header.toLowerCase()], "the header value"); + }); + }); + + it("drops the header when redirected to a different host (same hostname and different port)", function () { + app.get("/a", redirectsTo(302, "http://localhost:3600/b")); + app.get("/b", function (req, res) { + res.end(JSON.stringify(req.headers)); }); - }); - it("drops the header when redirected to a different host", function () { - app.get("/a", redirectsTo(302, "http://127.0.0.1:3600/b")); - app.get("/b", function (req, res) { - res.end(JSON.stringify(req.headers)); - }); + var opts = url.parse("http://127.0.0.1:3600/a"); + opts.headers = { host: "localhost" }; + opts.headers[header] = "the header value"; - var opts = url.parse("http://localhost:3600/a"); - opts.headers = { - authorization: "bearer my-token-1234", - }; + return server.start(app) + .then(asPromise(function (resolve, reject) { + http.get(opts, resolve).on("error", reject); + })) + .then(asPromise(function (resolve, reject, res) { + res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); + })) + .then(function (str) { + var body = JSON.parse(str); + assert.equal(body.host, "localhost:3600"); + assert.equal(body[header.toLowerCase()], undefined); + }); + }); - return server.start(app) - .then(asPromise(function (resolve, reject) { - http.get(opts, resolve).on("error", reject); - })) - .then(asPromise(function (resolve, reject, res) { - res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); - })) - .then(function (str) { - var body = JSON.parse(str); - assert.equal(body.host, "127.0.0.1:3600"); - assert.equal(body.authorization, undefined); + it("drops the header when redirected to a different host", function () { + app.get("/a", redirectsTo(302, "http://127.0.0.1:3600/b")); + app.get("/b", function (req, res) { + res.end(JSON.stringify(req.headers)); }); - }); - it("drops the header when redirected from a different host via header", function () { - app.get("/a", redirectsTo(302, "http://127.0.0.1:3600/b")); - app.get("/b", function (req, res) { - res.end(JSON.stringify(req.headers)); - }); + var opts = url.parse("http://localhost:3600/a"); + opts.headers = {}; + opts.headers[header] = "the header value"; - var opts = url.parse("http://127.0.0.1:3600/a"); - opts.headers = { - host: "localhost", - authorization: "bearer my-token-1234", - }; + return server.start(app) + .then(asPromise(function (resolve, reject) { + http.get(opts, resolve).on("error", reject); + })) + .then(asPromise(function (resolve, reject, res) { + res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); + })) + .then(function (str) { + var body = JSON.parse(str); + assert.equal(body.host, "127.0.0.1:3600"); + assert.equal(body[header.toLowerCase()], undefined); + }); + }); - return server.start(app) - .then(asPromise(function (resolve, reject) { - http.get(opts, resolve).on("error", reject); - })) - .then(asPromise(function (resolve, reject, res) { - res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); - })) - .then(function (str) { - var body = JSON.parse(str); - assert.equal(body.host, "127.0.0.1:3600"); - assert.equal(body.authorization, undefined); + it("drops the header when redirected from a different host via header", function () { + app.get("/a", redirectsTo(302, "http://127.0.0.1:3600/b")); + app.get("/b", function (req, res) { + res.end(JSON.stringify(req.headers)); }); + + var opts = url.parse("http://127.0.0.1:3600/a"); + opts.headers = { host: "localhost" }; + opts.headers[header] = "the header value"; + + return server.start(app) + .then(asPromise(function (resolve, reject) { + http.get(opts, resolve).on("error", reject); + })) + .then(asPromise(function (resolve, reject, res) { + res.pipe(concat({ encoding: "string" }, resolve)).on("error", reject); + })) + .then(function (str) { + var body = JSON.parse(str); + assert.equal(body.host, "127.0.0.1:3600"); + assert.equal(body[header.toLowerCase()], undefined); + }); + }); }); });
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-74fj-2j2h-c42qghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-0155ghsaADVISORY
- cert-portal.siemens.com/productcert/pdf/ssa-637483.pdfghsax_refsource_CONFIRMWEB
- github.com/follow-redirects/follow-redirects/commit/8b347cbcef7c7b72a6e9be20f5710c17d6163c22ghsax_refsource_MISCWEB
- huntr.dev/bounties/fc524e4b-ebb6-427d-ab67-a64181020406ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.