Introduction
In a Node.js application's package-lock.json, we discovered a high-severity prototype pollution vulnerability in Axios 1.13.2. The vulnerability, tracked as CVE-2026-25639, exists in Axios's mergeConfig function, which handles the merging of HTTP client configuration objects. When processing configuration objects containing the special __proto__ key, Axios fails to sanitize this dangerous property, allowing attackers to pollute JavaScript's prototype chain and trigger denial of service conditions.
This matters because Axios is one of the most widely used HTTP clients in the JavaScript ecosystem, with millions of downloads per week. Any application using Axios to make HTTP requests with user-influenced configuration—whether through API parameters, environment variables, or configuration files—could be vulnerable to this attack pattern.
The Vulnerability Explained
Prototype pollution is a JavaScript-specific vulnerability that exploits the language's prototype-based inheritance model. In JavaScript, nearly all objects inherit from Object.prototype, and modifying this prototype affects every object in the application.
The vulnerable code path exists in Axios's configuration merging logic. When Axios merges configuration objects (for example, combining default settings with request-specific options), it performs a recursive merge without properly filtering dangerous keys. Here's what happens:
// Vulnerable pattern in Axios 1.13.2 mergeConfig
function mergeConfig(config1, config2) {
// Simplified representation of the vulnerable logic
const result = {};
for (const key in config2) {
// No check for __proto__, constructor, or prototype
result[key] = config2[key];
}
return result;
}
The specific problem is that when config2 contains a __proto__ key, this code inadvertently modifies the prototype chain rather than just setting a property on the result object. An attacker could exploit this by providing a malicious configuration object:
const maliciousConfig = {
url: 'https://api.example.com',
__proto__: {
isAdmin: true,
polluted: 'This affects all objects!'
}
};
axios.request(maliciousConfig);
// Now ALL objects in the application inherit { isAdmin: true, polluted: '...' }
Real-World Attack Scenario
Consider an application that allows users to configure HTTP request settings through an API:
// Vulnerable application code using Axios 1.13.2
app.post('/api/fetch-data', async (req, res) => {
const userConfig = req.body.requestConfig; // User-controlled input
try {
const response = await axios.request({
baseURL: 'https://internal-api.example.com',
...userConfig // Merges user configuration
});
res.json(response.data);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
An attacker could send a POST request with this payload:
{
"requestConfig": {
"timeout": 5000,
"__proto__": {
"isAdmin": true,
"toString": null
}
}
}
This attack would:
1. Pollute the prototype chain: Every object in the application now has isAdmin: true
2. Break core functionality: Setting toString to null causes crashes when any code calls .toString() on objects
3. Cause denial of service: The application becomes unstable, with errors cascading through unrelated components
4. Persist across requests: In Node.js, the polluted prototype affects all subsequent requests until the process restarts
The impact is severe because the pollution affects the entire JavaScript runtime, not just the Axios configuration. This can lead to application crashes, memory leaks, authentication bypasses (if security checks rely on object properties), and complete service disruption.
The Fix
The fix involved upgrading Axios from version 1.13.2 to 1.18.0, which implements comprehensive prototype pollution protections. Let's examine the specific changes in package-lock.json:
Before (Vulnerable):
"node_modules/axios": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
}
After (Patched):
"node_modules/axios": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz",
"integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.16.0",
"form-data": "^4.0.5",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^2.1.0"
}
}
Key Security Improvements
The upgrade to Axios 1.18.0 introduces several critical security enhancements:
-
Prototype Key Filtering: The
mergeConfigfunction now explicitly checks for and rejects dangerous keys like__proto__,constructor, andprototypebefore performing merges. -
Enhanced Dependency Security:
-follow-redirectsupgraded from 1.15.6 to 1.16.0 (includes security patches)
-form-dataupgraded from 4.0.4 to 4.0.5 (improved boundary handling)
-proxy-from-envupgraded from 1.1.0 to 2.1.0 (better environment variable parsing)
- New dependencyhttps-proxy-agent5.0.1 added (provides secure proxy handling with additional validation) -
Safe Object Creation: The patched version uses
Object.create(null)for internal configuration objects, creating objects without a prototype chain that can't be polluted.
The addition of agent-base 6.0.2 and https-proxy-agent 5.0.1 as new dependencies provides an additional security layer. These packages implement secure proxy handling with built-in validation that prevents configuration injection attacks:
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
}
}
The fix is scoped to package.json and package-lock.json, ensuring that all instances of Axios in the dependency tree are upgraded. This approach prevents version conflicts and ensures comprehensive protection across the entire application.
How the Patched Code Prevents the Attack
In Axios 1.18.0, the mergeConfig function now includes explicit prototype pollution prevention:
// Patched mergeConfig in Axios 1.18.0 (conceptual representation)
function mergeConfig(config1, config2) {
const result = Object.create(null); // No prototype chain
for (const key in config2) {
// Explicitly block dangerous keys
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue; // Skip dangerous keys
}
result[key] = config2[key];
}
return result;
}
This change ensures that even if an attacker provides a malicious configuration object with __proto__ keys, those keys are filtered out before the merge operation, completely preventing prototype pollution.
Prevention & Best Practices
To prevent prototype pollution vulnerabilities in your JavaScript applications:
1. Keep Dependencies Updated
Regularly audit and update dependencies, especially security-critical libraries like HTTP clients. Use automated tools to monitor for CVEs:
npm audit
npm outdated
2. Validate Configuration Objects
When accepting user input that influences configuration objects, implement strict validation:
function sanitizeConfig(userConfig) {
const dangerousKeys = ['__proto__', 'constructor', 'prototype'];
const sanitized = {};
for (const key in userConfig) {
if (dangerousKeys.includes(key)) {
throw new Error(`Forbidden key: ${key}`);
}
sanitized[key] = userConfig[key];
}
return sanitized;
}
// Use sanitized config with Axios
const safeConfig = sanitizeConfig(req.body.requestConfig);
const response = await axios.request(safeConfig);
3. Use Safe Object Creation
When creating dictionary-like objects, use Object.create(null) to avoid prototype chain issues:
const config = Object.create(null);
config.timeout = 5000;
config.headers = { 'Content-Type': 'application/json' };
// This object has no prototype, preventing pollution
4. Implement Object Freezing
For critical configuration objects, use Object.freeze() to prevent modifications:
const baseConfig = Object.freeze({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: { 'User-Agent': 'MyApp/1.0' }
});
// Any attempt to modify this object will fail silently (or throw in strict mode)
5. Use Static Analysis Tools
Integrate tools that can detect prototype pollution patterns:
- Semgrep: Rules for detecting unsafe object merging patterns
- ESLint: Plugins like
eslint-plugin-securityfor security anti-patterns - Snyk: Dependency vulnerability scanning with automated fix PRs
- Trivy: Container and dependency scanning for CVEs
6. Follow OWASP Guidelines
Refer to OWASP's guidance on prototype pollution:
- Validate all external input before using it in object operations
- Use allowlists for permitted configuration keys
- Avoid recursive merge operations on untrusted data
- Implement Content Security Policy (CSP) to limit damage from successful attacks
7. Implement Defense in Depth
Combine multiple protective layers:
// Layer 1: Input validation
const allowedKeys = ['url', 'method', 'timeout', 'headers', 'data'];
const validatedConfig = Object.keys(userInput)
.filter(key => allowedKeys.includes(key))
.reduce((obj, key) => {
obj[key] = userInput[key];
return obj;
}, {});
// Layer 2: Use patched library
const response = await axios.request(validatedConfig);
// Layer 3: Error handling
try {
// Process response
} catch (error) {
logger.error('Request failed', { error, config: validatedConfig });
// Don't expose internal details to user
throw new Error('Request failed');
}
Key Takeaways
- Axios 1.13.2's
mergeConfigfunction fails to sanitize__proto__keys, allowing prototype chain pollution that affects all objects in the Node.js runtime - CVE-2026-25639 is exploitable through any code path that merges user-controlled data into Axios configuration objects, including API endpoints, environment variables, or configuration files
- Upgrading to Axios 1.18.0 is essential as it implements explicit filtering of dangerous prototype keys (
__proto__,constructor,prototype) in configuration merging logic - The fix includes critical dependency updates:
follow-redirects1.16.0,form-data4.0.5,proxy-from-env2.1.0, and addshttps-proxy-agent5.0.1 for enhanced security controls - Prototype pollution attacks can cause cascading failures across unrelated application components, making this vulnerability particularly dangerous in production environments where a single malicious request can crash the entire service
How Orbis AppSec Detected This
- Source: User-controlled configuration objects merged into Axios request settings, potentially from HTTP request bodies, query parameters, or environment variables
- Sink:
axios.request()and related methods in application code that utilize the vulnerablemergeConfigfunction in Axios 1.13.2 - Missing control: No sanitization of prototype pollution keys (
__proto__,constructor,prototype) before configuration object merging; Axios 1.13.2 lacks built-in prototype key filtering - CWE: CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes)
- Fix: Upgraded Axios from 1.13.2 to 1.18.0, which implements explicit prototype key filtering in
mergeConfigand includes enhanced proxy handling viahttps-proxy-agent5.0.1
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
CVE-2026-25639 demonstrates how seemingly innocuous configuration merging logic can create severe security vulnerabilities in widely-used libraries. The prototype pollution vulnerability in Axios 1.13.2 could allow attackers to trigger denial of service conditions by polluting JavaScript's prototype chain through the __proto__ key in configuration objects.
The fix—upgrading to Axios 1.18.0—is straightforward but critical. This version implements comprehensive prototype pollution protections, including explicit filtering of dangerous keys and enhanced dependency security. Beyond applying this specific patch, developers should adopt defensive coding practices: validate all user input before using it in object operations, use safe object creation patterns, keep dependencies updated, and implement multiple layers of security controls.
Prototype pollution vulnerabilities are particularly insidious because they can affect seemingly unrelated parts of an application, making them difficult to debug and potentially catastrophic in production. By understanding this attack pattern and implementing proper protections, you can build more resilient JavaScript applications that withstand sophisticated attacks.
References
- CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
- OWASP Prototype Pollution Prevention Cheat Sheet
- Axios Security Documentation
- Semgrep Rules for Prototype Pollution Detection
- Node.js Security Best Practices
- fix: upgrade axios to 1.13.5, 0.30.3 (CVE-2026-25639)