VYPR
Medium severity4.8NVD Advisory· Published Apr 10, 2026· Updated May 12, 2026

CVE-2026-40175

CVE-2026-40175

Description

Axios is a promise based HTTP client for the browser and Node.js. Prior to 1.15.0 and 0.3.1, the Axios library is vulnerable to a specific "Gadget" attack chain that allows Prototype Pollution in any third-party dependency to be escalated into Remote Code Execution (RCE) or Full Cloud Compromise (via AWS IMDSv2 bypass). This vulnerability is fixed in 1.15.0 and 0.3.1.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
axiosnpm
>= 1.0.0, < 1.15.01.15.0
axiosnpm
< 0.31.00.31.0

Affected products

1
  • cpe:2.3:a:axios:axios:*:*:*:*:*:node.js:*:*
    Range: <0.31.0

Patches

2
03cdfc99e8db

fix: backport the fixes from the v1 branch (#10688)

https://github.com/axios/axiosJayApr 11, 2026via ghsa
8 files changed · +397 4
  • lib/adapters/http.js+7 4 modified
    @@ -19,6 +19,7 @@ var platform = require('../platform');
     var fromDataURI = require('../helpers/fromDataURI');
     var stream = require('stream');
     var estimateDataURLDecodedBytes = require('../helpers/estimateDataURLDecodedBytes.js');
    +var shouldBypassProxy = require('../helpers/shouldBypassProxy');
     
     var isHttps = /https:?/;
     
    @@ -46,9 +47,11 @@ function setProxy(options, configProxy, location) {
       if (!proxy && proxy !== false) {
         var proxyUrl = getProxyForUrl(location);
         if (proxyUrl) {
    -      proxy = url.parse(proxyUrl);
    -      // replace 'host' since the proxy object is not a URL object
    -      proxy.host = proxy.hostname;
    +      if (!shouldBypassProxy(location)) {
    +        proxy = url.parse(proxyUrl);
    +        // replace 'host' since the proxy object is not a URL object
    +        proxy.host = proxy.hostname;
    +      }
         }
       }
       if (proxy) {
    @@ -273,7 +276,7 @@ module.exports = function httpAdapter(config) {
         } else {
           options.hostname = parsed.hostname;
           options.port = parsed.port;
    -      setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
    +      setProxy(options, config.proxy, protocol + '//' + parsed.host + options.path);
         }
     
         var transport;
    
  • lib/core/dispatchRequest.js+5 0 modified
    @@ -6,6 +6,7 @@ var isCancel = require('../cancel/isCancel');
     var defaults = require('../defaults');
     var CanceledError = require('../cancel/CanceledError');
     var normalizeHeaderName = require('../helpers/normalizeHeaderName');
    +var sanitizeHeaderValue = require('../helpers/sanitizeHeaderValue');
     
     /**
      * Throws a `CanceledError` if cancellation has been requested.
    @@ -58,6 +59,10 @@ module.exports = function dispatchRequest(config) {
         }
       );
     
    +  utils.forEach(config.headers, function sanitizeHeaderConfigValue(value, header) {
    +    config.headers[header] = sanitizeHeaderValue(value);
    +  });
    +
       var adapter = config.adapter || defaults.adapter;
     
       return adapter(config).then(function onAdapterResolution(response) {
    
  • lib/helpers/sanitizeHeaderValue.js+22 0 added
    @@ -0,0 +1,22 @@
    +'use strict';
    +
    +var utils = require('../utils');
    +
    +var INVALID_HEADER_VALUE_RE = /[^\x09\x20-\x7E\x80-\xFF]/g;
    +var BOUNDARY_WHITESPACE_RE = /^[\x09\x20]+|[\x09\x20]+$/g;
    +
    +function sanitizeHeaderValue(value) {
    +  if (value === false || value == null) {
    +    return value;
    +  }
    +
    +  if (utils.isArray(value)) {
    +    return value.map(sanitizeHeaderValue);
    +  }
    +
    +  return String(value)
    +    .replace(INVALID_HEADER_VALUE_RE, '')
    +    .replace(BOUNDARY_WHITESPACE_RE, '');
    +}
    +
    +module.exports = sanitizeHeaderValue;
    
  • lib/helpers/shouldBypassProxy.js+133 0 added
    @@ -0,0 +1,133 @@
    +'use strict';
    +
    +var URL = require('url').URL;
    +
    +var DEFAULT_PORTS = {
    +  http: 80,
    +  https: 443,
    +  ws: 80,
    +  wss: 443,
    +  ftp: 21
    +};
    +
    +function parseNoProxyEntry(entry) {
    +  var entryHost = entry;
    +  var entryPort = 0;
    +
    +  if (entryHost.charAt(0) === '[') {
    +    var bracketIndex = entryHost.indexOf(']');
    +
    +    if (bracketIndex !== -1) {
    +      var host = entryHost.slice(1, bracketIndex);
    +      var rest = entryHost.slice(bracketIndex + 1);
    +
    +      if (rest.charAt(0) === ':' && /^\d+$/.test(rest.slice(1))) {
    +        entryPort = parseInt(rest.slice(1), 10);
    +      }
    +
    +      return [host, entryPort];
    +    }
    +  }
    +
    +  var firstColon = entryHost.indexOf(':');
    +  var lastColon = entryHost.lastIndexOf(':');
    +
    +  if (firstColon !== -1 && firstColon === lastColon && /^\d+$/.test(entryHost.slice(lastColon + 1))) {
    +    entryPort = parseInt(entryHost.slice(lastColon + 1), 10);
    +    entryHost = entryHost.slice(0, lastColon);
    +  }
    +
    +  return [entryHost, entryPort];
    +}
    +
    +function normalizeNoProxyHost(hostname) {
    +  if (!hostname) {
    +    return hostname;
    +  }
    +
    +  if (hostname.charAt(0) === '[' && hostname.charAt(hostname.length - 1) === ']') {
    +    hostname = hostname.slice(1, -1);
    +  }
    +
    +  return hostname.replace(/\.+$/, '');
    +}
    +
    +function isLoopbackIPv4(hostname) {
    +  var octets = hostname.split('.');
    +
    +  if (octets.length !== 4) {
    +    return false;
    +  }
    +
    +  if (octets[0] !== '127') {
    +    return false;
    +  }
    +
    +  return octets.every(function testOctet(octet) {
    +    return /^\d+$/.test(octet) && Number(octet) >= 0 && Number(octet) <= 255;
    +  });
    +}
    +
    +function isLoopbackHost(hostname) {
    +  return hostname === 'localhost' || hostname === '::1' || isLoopbackIPv4(hostname);
    +}
    +
    +module.exports = function shouldBypassProxy(location) {
    +  var parsed;
    +
    +  try {
    +    parsed = new URL(location);
    +  } catch (err) {
    +    return false;
    +  }
    +
    +  var noProxy = (process.env.no_proxy || process.env.NO_PROXY || '').toLowerCase();
    +
    +  if (!noProxy) {
    +    return false;
    +  }
    +
    +  if (noProxy === '*') {
    +    return true;
    +  }
    +
    +  var protocol = parsed.protocol.split(':', 1)[0];
    +  var port = parsed.port !== '' ? parseInt(parsed.port, 10) : (DEFAULT_PORTS[protocol] || 0);
    +  var hostname = normalizeNoProxyHost(parsed.hostname.toLowerCase());
    +
    +  return noProxy.split(/[\s,]+/).some(function testNoProxyEntry(entry) {
    +    if (!entry) {
    +      return false;
    +    }
    +
    +    var entryParts = parseNoProxyEntry(entry);
    +    var entryHost = normalizeNoProxyHost(entryParts[0]);
    +    var entryPort = entryParts[1];
    +
    +    if (entryHost === '*') {
    +      return true;
    +    }
    +
    +    if (!entryHost) {
    +      return false;
    +    }
    +
    +    if (entryPort && entryPort !== port) {
    +      return false;
    +    }
    +
    +    if (isLoopbackHost(hostname) && isLoopbackHost(entryHost)) {
    +      return true;
    +    }
    +
    +    if (entryHost.charAt(0) === '*') {
    +      entryHost = entryHost.slice(1);
    +    }
    +
    +    if (entryHost.charAt(0) === '.') {
    +      return hostname.slice(-entryHost.length) === entryHost;
    +    }
    +
    +    return hostname === entryHost;
    +  });
    +};
    
  • test/specs/headers.spec.js+13 0 modified
    @@ -112,4 +112,17 @@ describe('headers', function () {
           done();
         });
       });
    +
    +  it('should sanitize headers containing invalid characters', function (done) {
    +    axios('/foo', {
    +      headers: {
    +        'x-test': ' ok\r\nInjected: yes\t'
    +      }
    +    });
    +
    +    getAjaxRequest().then(function (request) {
    +      testHeaderValue(request.requestHeaders, 'x-test', 'okInjected: yes');
    +      done();
    +    });
    +  });
     });
    
  • test/unit/adapters/http.js+123 0 modified
    @@ -31,8 +31,39 @@ describe('supports http with nodejs', function () {
           proxy = null;
         }
         delete process.env.http_proxy;
    +    delete process.env.HTTP_PROXY;
         delete process.env.https_proxy;
         delete process.env.no_proxy;
    +    delete process.env.NO_PROXY;
    +  });
    +
    +  it('should sanitize request headers containing invalid characters', function (done) {
    +    server = http.createServer(function (req, res) {
    +      res.setHeader('Content-Type', 'text/plain');
    +      res.end(req.headers['x-test']);
    +    }).listen(4444, function () {
    +      axios.get('http://localhost:4444/', {
    +        headers: {
    +          'x-test': ' ok\r\nInjected: yes\t'
    +        }
    +      }).then(function (response) {
    +        assert.equal(response.data, 'okInjected: yes');
    +        done();
    +      }).catch(done);
    +    });
    +  });
    +
    +  it('should preserve request error for unavailable host with invalid characters', function (done) {
    +    axios.get('http://localhost:1/', {
    +      headers: {
    +        'x-test': 'ok\r\nInjected: yes'
    +      }
    +    }).then(function () {
    +      done(new Error('request should not succeed'));
    +    }).catch(function (error) {
    +      assert.notEqual(error.message, 'Invalid character in header content ["x-test"]');
    +      done();
    +    });
       });
     
       it('should throw an error if the timeout property is not parsable as a number', function (done) {
    @@ -967,6 +998,98 @@ describe('supports http with nodejs', function () {
         });
       });
     
    +  it('should not use proxy for localhost with trailing dot when listed in no_proxy', function (done) {
    +    var proxyRequests = 0;
    +
    +    proxy = http.createServer(function (request, response) {
    +      proxyRequests += 1;
    +      response.end('proxied');
    +    }).listen(4000, function () {
    +      process.env.http_proxy = 'http://localhost:4000/';
    +      process.env.HTTP_PROXY = 'http://localhost:4000/';
    +      process.env.no_proxy = 'localhost,127.0.0.1,::1';
    +      process.env.NO_PROXY = 'localhost,127.0.0.1,::1';
    +
    +      axios.get('http://localhost.:1/', {
    +        timeout: 100
    +      }).then(function () {
    +        done(new Error('request should not succeed'));
    +      }).catch(function () {
    +        assert.equal(proxyRequests, 0, 'should not use proxy for localhost with trailing dot');
    +        done();
    +      });
    +    });
    +  });
    +
    +  it('should not use proxy for bracketed IPv6 loopback when listed in no_proxy', function (done) {
    +    var proxyRequests = 0;
    +
    +    proxy = http.createServer(function (request, response) {
    +      proxyRequests += 1;
    +      response.end('proxied');
    +    }).listen(4000, function () {
    +      process.env.http_proxy = 'http://localhost:4000/';
    +      process.env.HTTP_PROXY = 'http://localhost:4000/';
    +      process.env.no_proxy = 'localhost,127.0.0.1,::1';
    +      process.env.NO_PROXY = 'localhost,127.0.0.1,::1';
    +
    +      axios.get('http://[::1]:1/', {
    +        timeout: 100
    +      }).then(function () {
    +        done(new Error('request should not succeed'));
    +      }).catch(function () {
    +        assert.equal(proxyRequests, 0, 'should not use proxy for IPv6 loopback');
    +        done();
    +      });
    +    });
    +  });
    +
    +  it('should not use proxy for 127.0.0.1 when no_proxy is localhost', function (done) {
    +    var proxyRequests = 0;
    +
    +    proxy = http.createServer(function (request, response) {
    +      proxyRequests += 1;
    +      response.end('proxied');
    +    }).listen(4000, function () {
    +      process.env.http_proxy = 'http://localhost:4000/';
    +      process.env.HTTP_PROXY = 'http://localhost:4000/';
    +      process.env.no_proxy = 'localhost';
    +      process.env.NO_PROXY = 'localhost';
    +
    +      axios.get('http://127.0.0.1:1/', {
    +        timeout: 100
    +      }).then(function () {
    +        done(new Error('request should not succeed'));
    +      }).catch(function () {
    +        assert.equal(proxyRequests, 0, 'should not use proxy for IPv4 loopback alias');
    +        done();
    +      });
    +    });
    +  });
    +
    +  it('should not use proxy for [::1] when no_proxy is localhost', function (done) {
    +    var proxyRequests = 0;
    +
    +    proxy = http.createServer(function (request, response) {
    +      proxyRequests += 1;
    +      response.end('proxied');
    +    }).listen(4000, function () {
    +      process.env.http_proxy = 'http://localhost:4000/';
    +      process.env.HTTP_PROXY = 'http://localhost:4000/';
    +      process.env.no_proxy = 'localhost';
    +      process.env.NO_PROXY = 'localhost';
    +
    +      axios.get('http://[::1]:1/', {
    +        timeout: 100
    +      }).then(function () {
    +        done(new Error('request should not succeed'));
    +      }).catch(function () {
    +        assert.equal(proxyRequests, 0, 'should not use proxy for IPv6 loopback alias');
    +        done();
    +      });
    +    });
    +  });
    +
       it('should use proxy for domains not in no_proxy', function (done) {
         server = http.createServer(function (req, res) {
           res.setHeader('Content-Type', 'text/html; charset=UTF-8');
    
  • test/unit/helpers/sanitizeHeaderValue.js+20 0 added
    @@ -0,0 +1,20 @@
    +var assert = require('assert');
    +var sanitizeHeaderValue = require('../../../lib/helpers/sanitizeHeaderValue');
    +
    +describe('helpers::sanitizeHeaderValue', function () {
    +  it('should remove invalid header characters', function () {
    +    assert.strictEqual(sanitizeHeaderValue('ok\r\nInjected: yes'), 'okInjected: yes');
    +    assert.strictEqual(sanitizeHeaderValue('ok\x01bad'), 'okbad');
    +  });
    +
    +  it('should remove boundary whitespace', function () {
    +    assert.strictEqual(sanitizeHeaderValue(' value\t'), 'value');
    +  });
    +
    +  it('should sanitize array values recursively', function () {
    +    assert.deepStrictEqual(
    +      sanitizeHeaderValue([' safe=1 ', 'unsafe=1\nInjected: true']),
    +      ['safe=1', 'unsafe=1Injected: true']
    +    );
    +  });
    +});
    
  • test/unit/helpers/shouldBypassProxy.js+74 0 added
    @@ -0,0 +1,74 @@
    +var assert = require('assert');
    +var shouldBypassProxy = require('../../../lib/helpers/shouldBypassProxy');
    +
    +var originalNoProxy = process.env.no_proxy;
    +var originalNOProxy = process.env.NO_PROXY;
    +
    +function setNoProxy(value) {
    +  process.env.no_proxy = value;
    +  process.env.NO_PROXY = value;
    +}
    +
    +describe('helpers::shouldBypassProxy', function () {
    +  afterEach(function () {
    +    if (originalNoProxy === undefined) {
    +      delete process.env.no_proxy;
    +    } else {
    +      process.env.no_proxy = originalNoProxy;
    +    }
    +
    +    if (originalNOProxy === undefined) {
    +      delete process.env.NO_PROXY;
    +    } else {
    +      process.env.NO_PROXY = originalNOProxy;
    +    }
    +  });
    +
    +  it('should bypass proxy for localhost with a trailing dot', function () {
    +    setNoProxy('localhost,127.0.0.1,::1');
    +    assert.strictEqual(shouldBypassProxy('http://localhost.:8080/'), true);
    +  });
    +
    +  it('should bypass proxy for bracketed ipv6 loopback', function () {
    +    setNoProxy('localhost,127.0.0.1,::1');
    +    assert.strictEqual(shouldBypassProxy('http://[::1]:8080/'), true);
    +  });
    +
    +  it('should support bracketed ipv6 entries in no_proxy', function () {
    +    setNoProxy('[::1]');
    +    assert.strictEqual(shouldBypassProxy('http://[::1]:8080/'), true);
    +  });
    +
    +  it('should match wildcard and explicit ports', function () {
    +    setNoProxy('*.example.com,localhost:8080');
    +
    +    assert.strictEqual(shouldBypassProxy('http://api.example.com/'), true);
    +    assert.strictEqual(shouldBypassProxy('http://localhost:8080/'), true);
    +    assert.strictEqual(shouldBypassProxy('http://localhost:8081/'), false);
    +  });
    +
    +  it('should treat localhost and loopback IP aliases as equivalent', function () {
    +    setNoProxy('localhost');
    +
    +    assert.strictEqual(shouldBypassProxy('http://127.0.0.1:8080/'), true);
    +    assert.strictEqual(shouldBypassProxy('http://[::1]:8080/'), true);
    +
    +    setNoProxy('127.0.0.1');
    +
    +    assert.strictEqual(shouldBypassProxy('http://localhost:8080/'), true);
    +    assert.strictEqual(shouldBypassProxy('http://[::1]:8080/'), true);
    +
    +    setNoProxy('::1');
    +
    +    assert.strictEqual(shouldBypassProxy('http://localhost:8080/'), true);
    +    assert.strictEqual(shouldBypassProxy('http://127.0.0.1:8080/'), true);
    +  });
    +
    +  it('should keep loopback alias matching port-aware', function () {
    +    setNoProxy('localhost:8080');
    +
    +    assert.strictEqual(shouldBypassProxy('http://127.0.0.1:8080/'), true);
    +    assert.strictEqual(shouldBypassProxy('http://[::1]:8080/'), true);
    +    assert.strictEqual(shouldBypassProxy('http://127.0.0.1:8081/'), false);
    +  });
    +});
    
363185461b90

fix: unrestricted cloud metadata exfiltration via header injection chain (#10660)

https://github.com/axios/axiosJayApr 6, 2026via ghsa
6 files changed · +120 16
  • lib/core/AxiosHeaders.js+35 3 modified
    @@ -5,18 +5,49 @@ import parseHeaders from '../helpers/parseHeaders.js';
     
     const $internals = Symbol('internals');
     
    +const isValidHeaderValue = (value) => !/[\r\n]/.test(value);
    +
    +function assertValidHeaderValue(value, header) {
    +  if (value === false || value == null) {
    +    return;
    +  }
    +
    +  if (utils.isArray(value)) {
    +    value.forEach((v) => assertValidHeaderValue(v, header));
    +    return;
    +  }
    +
    +  if (!isValidHeaderValue(String(value))) {
    +    throw new Error(`Invalid character in header content ["${header}"]`);
    +  }
    +}
    +
     function normalizeHeader(header) {
       return header && String(header).trim().toLowerCase();
     }
     
    +function stripTrailingCRLF(str) {
    +  let end = str.length;
    +
    +  while (end > 0) {
    +    const charCode = str.charCodeAt(end - 1);
    +
    +    if (charCode !== 10 && charCode !== 13) {
    +      break;
    +    }
    +
    +    end -= 1;
    +  }
    +
    +  return end === str.length ? str : str.slice(0, end);
    +}
    +
     function normalizeValue(value) {
       if (value === false || value == null) {
         return value;
       }
     
    -  return utils.isArray(value)
    -    ? value.map(normalizeValue)
    -    : String(value).replace(/[\r\n]+$/, '');
    +  return utils.isArray(value) ? value.map(normalizeValue) : stripTrailingCRLF(String(value));
     }
     
     function parseTokens(str) {
    @@ -98,6 +129,7 @@ class AxiosHeaders {
             _rewrite === true ||
             (_rewrite === undefined && self[key] !== false)
           ) {
    +        assertValidHeaderValue(_value, _header);
             self[key || _header] = normalizeValue(_value);
           }
         }
    
  • lib/core/Axios.js+19 3 modified
    @@ -46,13 +46,29 @@ class Axios {
             Error.captureStackTrace ? Error.captureStackTrace(dummy) : (dummy = new Error());
     
             // slice off the Error: ... line
    -        const stack = dummy.stack ? dummy.stack.replace(/^.+\n/, '') : '';
    +        const stack = (() => {
    +          if (!dummy.stack) {
    +            return '';
    +          }
    +
    +          const firstNewlineIndex = dummy.stack.indexOf('\n');
    +
    +          return firstNewlineIndex === -1 ? '' : dummy.stack.slice(firstNewlineIndex + 1);
    +        })();
             try {
               if (!err.stack) {
                 err.stack = stack;
                 // match without the 2 top stack lines
    -          } else if (stack && !String(err.stack).endsWith(stack.replace(/^.+\n.+\n/, ''))) {
    -            err.stack += '\n' + stack;
    +          } else if (stack) {
    +            const firstNewlineIndex = stack.indexOf('\n');
    +            const secondNewlineIndex =
    +              firstNewlineIndex === -1 ? -1 : stack.indexOf('\n', firstNewlineIndex + 1);
    +            const stackWithoutTwoTopLines =
    +              secondNewlineIndex === -1 ? '' : stack.slice(secondNewlineIndex + 1);
    +
    +            if (!String(err.stack).endsWith(stackWithoutTwoTopLines)) {
    +              err.stack += '\n' + stack;
    +            }
               }
             } catch (e) {
               // ignore the case where "stack" is an un-writable property
    
  • tests/browser/adapter.browser.test.js+16 1 modified
    @@ -14,6 +14,7 @@ class MockXMLHttpRequest {
         this.upload = {
           addEventListener() {},
         };
    +    this.requestHeaders = {};
       }
     
       open(method, url, async = true) {
    @@ -22,7 +23,9 @@ class MockXMLHttpRequest {
         this.async = async;
       }
     
    -  setRequestHeader() {}
    +  setRequestHeader(key, value) {
    +    this.requestHeaders[key] = value;
    +  }
     
       addEventListener() {}
     
    @@ -175,4 +178,16 @@ describe('adapter (vitest browser)', () => {
         request.respondWith();
         await responsePromise;
       });
    +
    +  it('should reject request headers containing CRLF characters', async () => {
    +    await expect(
    +      axios('/foo', {
    +        headers: {
    +          'x-test': 'ok\r\nInjected: yes',
    +        },
    +      })
    +    ).rejects.toThrow(/Invalid character in header content/);
    +
    +    expect(requests.length).toBe(0);
    +  });
     });
    
  • tests/unit/adapters/fetch.test.js+11 0 modified
    @@ -26,6 +26,17 @@ const fetchAxios = axios.create({
     });
     
     describe.runIf(typeof fetch === 'function')('supports fetch with nodejs', () => {
    +  it('should reject request headers containing CRLF characters', async () => {
    +    await assert.rejects(
    +      fetchAxios.get(`${LOCAL_SERVER_URL}/`, {
    +        headers: {
    +          'x-test': 'ok\r\nInjected: yes',
    +        },
    +      }),
    +      /(invalid.*header|header.*invalid)/i
    +    );
    +  });
    +
       describe('responses', () => {
         it('should support text response type', async () => {
           const originalData = 'my data';
    
  • tests/unit/adapters/http.test.js+11 0 modified
    @@ -125,6 +125,17 @@ describe('supports http with nodejs', () => {
         }
       });
     
    +  it('should reject request headers containing CRLF characters', async () => {
    +    await assert.rejects(
    +      axios.get('http://localhost:1/', {
    +        headers: {
    +          'x-test': 'ok\r\nInjected: yes',
    +        },
    +      }),
    +      /Invalid character in header content/
    +    );
    +  });
    +
       it('should parse the timeout property', async () => {
         const server = await startHTTPServer(
           (req, res) => {
    
  • tests/unit/axiosHeaders.test.js+28 9 modified
    @@ -85,19 +85,38 @@ describe('AxiosHeaders', () => {
         });
     
         const runIfNode18OrHigher = nodeMajorVersion >= 18 ? it : it.skip;
    -    runIfNode18OrHigher('should support setting multiple header values from an iterable source', () => {
    +    runIfNode18OrHigher(
    +      'should support setting multiple header values from an iterable source',
    +      () => {
    +        const headers = new AxiosHeaders();
    +        const nativeHeaders = new Headers();
    +
    +        nativeHeaders.append('set-cookie', 'foo');
    +        nativeHeaders.append('set-cookie', 'bar');
    +        nativeHeaders.append('set-cookie', 'baz');
    +        nativeHeaders.append('y', 'qux');
    +
    +        headers.set(nativeHeaders);
    +
    +        assert.deepStrictEqual(headers.get('set-cookie'), ['foo', 'bar', 'baz']);
    +        assert.strictEqual(headers.get('y'), 'qux');
    +      }
    +    );
    +
    +    it('should throw on CRLF in header value', () => {
           const headers = new AxiosHeaders();
    -      const nativeHeaders = new Headers();
     
    -      nativeHeaders.append('set-cookie', 'foo');
    -      nativeHeaders.append('set-cookie', 'bar');
    -      nativeHeaders.append('set-cookie', 'baz');
    -      nativeHeaders.append('y', 'qux');
    +      assert.throws(() => {
    +        headers.set('x-test', 'safe\r\nInjected: true');
    +      }, /Invalid character in header content/);
    +    });
     
    -      headers.set(nativeHeaders);
    +    it('should throw on CRLF in any array header value', () => {
    +      const headers = new AxiosHeaders();
     
    -      assert.deepStrictEqual(headers.get('set-cookie'), ['foo', 'bar', 'baz']);
    -      assert.strictEqual(headers.get('y'), 'qux');
    +      assert.throws(() => {
    +        headers.set('set-cookie', ['safe=1', 'unsafe=1\nInjected: true']);
    +      }, /Invalid character in header content/);
         });
       });
     
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

11

News mentions

1