{"id":"CVE-2026-40895","kind":"vulnerability","aliases":["CVE-2026-40895","GHSA-r4q5-vmmm-2653"],"related":[],"title":"follow-redirects leaks Custom Authentication Headers to Cross-Domain Redirect Targets","description":"## Summary\n\nWhen an HTTP request follows a cross-domain redirect (301/302/307/308), `follow-redirects` only strips `authorization`, `proxy-authorization`, and `cookie` headers (matched by regex at index.js:469-476). Any custom authentication header (e.g., `X-API-Key`, `X-Auth-Token`, `Api-Key`, `Token`) is forwarded verbatim to the redirect target.\n\nSince `follow-redirects` is the redirect-handling dependency for **axios** (105K+ stars), this vulnerability affects the entire axios ecosystem.\n\n## Affected Code\n\n`index.js`, lines 469-476:\n\n```javascript\nif (redirectUrl.protocol !== currentUrlParts.protocol &&\n   redirectUrl.protocol !== \"https:\" ||\n   redirectUrl.host !== currentHost &&\n   !isSubdomain(redirectUrl.host, currentHost)) {\n  removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this._options.headers);\n}\n```\n\nThe regex only matches `authorization`, `proxy-authorization`, and `cookie`. Custom headers like `X-API-Key` are not matched.\n\n## Attack Scenario\n\n1. App uses axios with custom auth header: `headers: { 'X-API-Key': 'sk-live-secret123' }`\n2. Server returns `302 Location: https://evil.com/steal`\n3. follow-redirects sends `X-API-Key: sk-live-secret123` to `evil.com`\n4. Attacker captures the API key\n\n## Impact\n\nAny custom auth header set via axios leaks on cross-domain redirect. Extremely common pattern. Affects all axios users in Node.js.\n\n## Suggested Fix\n\nAdd a `sensitiveHeaders` option that users can extend, or strip ALL non-standard headers on cross-domain redirect.\n\n## Disclosure\n\nSource code review, manually verified. Found 2026-03-20.","summary":"follow-redirects strips only authorization, proxy-authorization and cookie headers when a request follows a cross-domain redirect. Custom authentication headers such as X-API-Key are sent unchanged to the redirect target, so that server can capture them.","severity":"high","cvss":7.5,"epss":0.00486,"exploited":false,"exploited_at":null,"products":[{"name":"follow-redirects","fixed":["1.16.0"],"affected":"<= 1.15.11","ecosystem":"npm"},{"name":"follow-redirects project follow-redirects","fixed":["1.16.0"],"affected":"< 1.16.0","ecosystem":"vendor"}],"ecosystems":["npm","vendor"],"tags":["axios","cwe-200","follow-redirects","node.js","npm","package"],"not_affected_if":["no-custom-auth-headers","same-origin-requests-only"],"how_to_check":"- Find the installed version with `npm ls follow-redirects` and check whether it is `1.15.11` or older.\n- Check whether axios or another HTTP client sends API keys or tokens in custom headers (for example `X-API-Key`) and whether those requests can be redirected to other hosts.","fix":"- follow-redirects: move to `1.16.0`.","status":"open","published_at":"2026-04-14T01:11:11+00:00","first_seen_at":"2026-11-02T23:19:56+00:00","triaged_at":"2026-11-02T23:21:40+00:00","updated_at":"2026-11-02T23:35:57+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-02T23:21:40Z","model":"claude-haiku-5-5","output":{"fix":"- follow-redirects: move to `1.16.0`.","reach":"internet","title":"follow-redirects: custom auth headers forwarded to cross-domain redirect targets","impact":"medium","summary":"follow-redirects strips only authorization, proxy-authorization and cookie headers when a request follows a cross-domain redirect. Custom authentication headers such as X-API-Key are sent unchanged to the redirect target, so that server can capture them.","audience":"developers","category":"package","nicknames":[],"who_cares":["npm","follow-redirects","axios","node.js"],"confidence":0.8,"fix_status":"available","needs_auth":"unknown","worst_case":"API keys and tokens in custom headers are sent to attacker-controlled hosts","analyst_note":"","how_to_check":"- Find the installed version with `npm ls follow-redirects` and check whether it is `1.15.11` or older.\n- Check whether axios or another HTTP client sends API keys or tokens in custom headers (for example `X-API-Key`) and whether those requests can be redirected to other hosts.","plain_action":"","needs_analyst":false,"not_affected_if":["no-custom-auth-headers","same-origin-requests-only"],"who_is_affected":"Applications that use follow-redirects, including through axios, and send secrets in custom headers to URLs that can return a cross-domain redirect. Requests that carry no custom credentials, or that only call hosts the team controls, have less exposure. The sources do not say how an attacker would cause the redirect, beyond a server returning a 3xx response.","user_interaction":"no","needs_special_setup":"no","severity_if_unknown":"medium"},"cost_usd":0.000765,"input_tokens":4792,"output_tokens":572,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-03':305C '-20':306C '-200':37B '-2026':15A,23A '-40895':16A,24A '-476':115C,166C '/i':182C '/steal':230C '1':206C '105k':152C '2':223C '2026':304C '2653':21A '3':231C '301/302/307/308':97C '302':226C '4':246C '469':165C 'add':277C 'affect':156C,161C,269C 'api':72B,123C,130C,199C,217C,238C,250C 'api-key':129C 'app':207C 'attack':204C,247C 'auth':127C,212C,255C 'authent':6A,66B,118C 'author':49B,52B,103C,106C,180C,188C,191C 'axio':35B,151C,159C,209C,259C,271C 'captur':85B,248C 'code':162C,299C 'common':267C 'cooki':54B,108C,181C,193C 'cross':10A,62B,94C,263C,294C 'cross-domain':9A,61B,93C,262C,293C 'currenthost':174C,177C 'currenturlparts.protocol':170C 'custom':5A,65B,117C,194C,211C,254C 'cve':14A,22A 'cwe':36B 'depend':149C 'disclosur':297C 'domain':11A,63B,95C,264C,295C 'e.g':120C 'ecosystem':160C 'entir':158C 'evil.com':229C,245C 'evil.com/steal':228C 'extend':284C 'extrem':266C 'fix':276C 'follow':2A,26A,29A,33A,39B,45B,59B,91C,99C,142C,233C 'follow-redirect':1A,38B,44B,98C,141C,232C 'follow-redirects':25A,28A,32A 'forward':134C 'found':303C 'ghsa':18A 'ghsa-r4q5-vmmm':17A 'handl':148C 'header':7A,55B,67B,109C,119C,195C,213C,214C,256C,291C 'http':89C 'https':172C 'impact':252C 'index.js':163C 'index.js:469':114C 'issubdomain':175C 'javascript':167C 'key':73B,124C,131C,200C,218C,239C,251C 'leak':4A,260C 'like':196C 'line':164C 'live':221C,242C 'locat':227C 'manual':301C 'match':110C,187C,203C 'node.js':41B,274C 'non':289C 'non-standard':288C 'npm':42B 'option':280C 'packag':43B 'pattern':268C 'project':31A 'proxi':51B,105C,179C,190C 'proxy-author':50B,104C,189C 'r4q5':19A 'redirect':3A,12A,40B,46B,64B,79B,96C,100C,138C,143C,147C,234C,265C,296C 'redirect-handl':146C 'redirects':27A,30A,34A 'redirecturl.host':173C,176C 'redirecturl.protocol':169C,171C 'regex':112C,185C 'removematchinghead':178C 'request':58B,90C 'return':225C 'review':300C 'scenario':205C 'secret123':222C,243C 'send':235C 'sensitivehead':279C 'sent':75B 'server':83B,224C 'set':257C 'sinc':140C 'sk':220C,241C 'sk-live-secret123':219C,240C 'sourc':298C 'standard':290C 'star':153C 'strip':47B,102C,286C 'suggest':275C 'summari':86C 'target':13A,80B,139C 'this._options.headers':183C 'token':128C,132C 'unchang':76B 'use':208C 'user':272C,282C 'verbatim':135C 'verifi':302C 'via':258C 'vmmm':20A 'vulner':155C 'x':71B,122C,126C,198C,216C,237C 'x-api-key':70B,121C,197C,215C,236C 'x-auth-token':125C","nicknames":[],"mitigations":[],"who_affected":"Applications that use follow-redirects, including through axios, and send secrets in custom headers to URLs that can return a cross-domain redirect. Requests that carry no custom credentials, or that only call hosts the team controls, have less exposure. The sources do not say how an attacker would cause the redirect, beyond a server returning a 3xx response.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["followredirects","followredirectsprojectfollowredirects","projectfollowredirects"],"ptokens":["follow","project","redirects"],"labels":["axios","cwe200","followredirects","high","nodejs","npm","package","vendor"],"first_public_at":"2026-04-13T11:04:03+00:00","kev":null,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","cvss_by":"security-advisories@github.com","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-r4q5-vmmm-2653","url":"https://github.com/advisories/GHSA-r4q5-vmmm-2653","severity":"medium","published_at":"2026-04-14T01:11:11+00:00","modified_at":"2026-11-02T23:19:21+00:00","first_seen_at":"2026-11-02T23:19:56+00:00","fetched_at":"2026-11-03T05:24:26+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-40895","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-40895","severity":null,"published_at":"2026-04-21T21:16:44+00:00","modified_at":"2026-09-10T13:20:02+00:00","first_seen_at":"2026-11-02T23:35:57+00:00","fetched_at":"2026-11-02T23:35:57+00:00","note":null}],"documents":[{"id":54404,"url":"https://api.github.com/repos/follow-redirects/follow-redirects/security-advisories/GHSA-r4q5-vmmm-2653","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"},{"id":54405,"url":"https://github.com/follow-redirects/follow-redirects/security/advisories/GHSA-r4q5-vmmm-2653","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":"2026-04-13T11:04:03+00:00","relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":54406,"url":"https://github.com/follow-redirects/follow-redirects/commit/844c4d302ac963d29bdb5dc1754ec7df3d70d7f9","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"}],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}