How Prototype Pollution Enables HTTP Header Injection in Axios and How to Fix It
Introduction
In a recent security audit, a high-severity prototype pollution vulnerability was discovered in Axios 1.13.5 within the package-lock.json dependency tree. This vulnerability (CVE-2026-42035) allowed attackers to inject arbitrary HTTP headers into requests by exploiting how Axios merged user-controlled configuration objects without proper validation. The vulnerable code path accepted untrusted input and merged it directly into the request configuration, creating an attack surface that could enable header injection attacks, request smuggling, and potential man-in-the-middle exploitation.
This is particularly dangerous because Axios is one of the most widely used HTTP client libraries in the Node.js ecosystem, with millions of applications relying on it for API requests, webhooks, and external service communication. A vulnerability at this level affects the entire dependency chain.
The Vulnerability Explained
What is Prototype Pollution?
Prototype pollution is a JavaScript vulnerability where an attacker manipulates an object's prototype chain to inject or modify properties that affect all objects inheriting from that prototype. In the context of Axios, this occurs when configuration objects are merged without proper validation.
How It Manifests in Axios 1.13.5
The vulnerability in Axios 1.13.5 stems from how the library processes HTTP request configuration. When a developer creates a request with user-controlled configuration data, Axios merges these settings into its internal request object. The problem: this merging process didn't properly validate or restrict which properties could be set.
Consider a typical Axios usage pattern:
// Vulnerable code path in Axios 1.13.5
const userConfig = req.body.config; // Untrusted user input
axios.request(userConfig); // Configuration merged without validation
An attacker could craft a malicious payload like:
{
"headers": {
"__proto__": {
"X-Injected-Header": "malicious-value"
}
}
}
Through prototype pollution, this payload would inject X-Injected-Header into the prototype chain, causing it to appear in all subsequent HTTP requests made by the application—not just the current one. This is fundamentally different from a simple header injection; it's a persistent modification that affects the entire application's HTTP behavior.
Real-World Attack Scenario
Imagine an e-commerce application that allows users to customize their API requests through a settings panel. The application code might look like:
// User submits custom request settings
app.post('/api/configure', (req, res) => {
const userSettings = req.body;
// Application stores and later uses these settings
axios.request({
method: 'GET',
url: 'https://payment-api.example.com/process',
...userSettings // Vulnerable spread of untrusted data
});
});
An attacker could submit:
{
"headers": {
"__proto__": {
"X-Admin-Override": "true",
"Authorization": "Bearer attacker-token"
}
}
}
After this pollution, every subsequent payment request made by the application would include these injected headers, potentially:
- Bypassing authentication checks
- Triggering admin-level operations
- Redirecting requests to attacker-controlled servers
- Modifying sensitive headers like Host or Referer
The attack persists across all requests until the application restarts, making it particularly dangerous.
The Fix
The security team addressed this vulnerability by upgrading Axios from version 1.13.5 to 1.18.0. This upgrade introduced multiple layers of protection:
Changes in package-lock.json:
- "axios": "^1.13.5",
+ "axios": "^1.18.0",
Dependency Updates:
- "follow-redirects": "^1.15.11",
+ "follow-redirects": "^1.16.0",
"form-data": "^4.0.5",
- "proxy-from-env": "^1.1.0"
+ "https-proxy-agent": "^5.0.1",
+ "proxy-from-env": "^2.1.0"
What Changed and Why
-
Axios 1.18.0 Core Fix: The new version implements strict input validation in its configuration merging logic. Rather than blindly spreading user-provided configuration objects, Axios 1.18.0:
- Validates which properties are allowed in configuration objects
- Prevents modification of the prototype chain through configuration
- Uses safer object assignment patterns that don't traverse__proto__ -
follow-redirects 1.16.0: Updated to version 1.16.0 to ensure secure redirect handling without prototype pollution vulnerabilities in its own code path.
-
https-proxy-agent 5.0.1: The addition of this dependency provides secure proxy handling for HTTPS requests. This replaces the simpler proxy handling in older versions and includes built-in protections against header injection during proxy operations. The
agent-base6.0.2 dependency was also added to support this. -
proxy-from-env 2.1.0: Updated to the latest version with improved security hardening.
How the Fix Prevents the Attack
In Axios 1.18.0, when processing configuration:
// Pseudocode representing the fix
function mergeConfig(userConfig) {
const allowedProperties = ['method', 'url', 'headers', 'data', ...];
const safeConfig = {};
// Only copy explicitly allowed properties
for (const key of allowedProperties) {
if (key in userConfig) {
safeConfig[key] = userConfig[key];
}
}
// Headers are validated individually
if (userConfig.headers) {
safeConfig.headers = validateHeaders(userConfig.headers);
}
return safeConfig;
}
The attacker's __proto__ payload is now rejected because:
- __proto__ is not in the allowed properties list
- Even if it were nested in headers, the validateHeaders() function would reject it
- The configuration merge no longer uses unsafe patterns that traverse the prototype chain
Prevention & Best Practices
For Developers Using Axios
-
Always upgrade to patched versions: Keep Axios and all HTTP client libraries updated. Version 1.18.0+ is safe; avoid 1.13.5 and earlier.
-
Validate configuration sources: Never directly spread untrusted user input into Axios configuration:
```javascript
// ❌ UNSAFE
axios.request({ ...userProvidedConfig });
// ✅ SAFE
const safeConfig = {
method: userProvidedConfig.method || 'GET',
url: validateUrl(userProvidedConfig.url),
headers: sanitizeHeaders(userProvidedConfig.headers)
};
axios.request(safeConfig);
```
-
Use allowlists for configuration: Define exactly which properties users can configure:
javascript const ALLOWED_CONFIG_KEYS = ['method', 'url', 'timeout', 'responseType']; const filteredConfig = Object.keys(userConfig) .filter(key => ALLOWED_CONFIG_KEYS.includes(key)) .reduce((obj, key) => ({ ...obj, [key]: userConfig[key] }), {}); -
Implement header validation: Sanitize HTTP headers to prevent injection:
javascript function sanitizeHeaders(headers) { const sanitized = {}; for (const [key, value] of Object.entries(headers || {})) { // Reject prototype pollution attempts if (key === '__proto__' || key === 'constructor' || key === 'prototype') { continue; } // Validate header format if (/^[a-zA-Z0-9\-]+$/.test(key)) { sanitized[key] = String(value).substring(0, 1000); } } return sanitized; }
For Library Maintainers
-
Never trust object merging: Use
Object.assign()carefully with user input. Consider usingObject.create(null)for configuration objects to eliminate prototype chain access. -
Implement strict configuration schemas: Define and validate all configuration options against a schema before use.
-
Use static analysis tools: Integrate tools like Semgrep to detect prototype pollution patterns during development.
Security Tools and Detection
- Trivy: The scanner that detected this vulnerability in the PR can be integrated into your CI/CD pipeline
- Semgrep: Use rules to detect unsafe object merges and prototype pollution patterns
- npm audit: Run
npm auditregularly to identify vulnerable dependencies - Snyk: Provides real-time vulnerability monitoring for Node.js projects
Key Takeaways
-
Prototype pollution in Axios 1.13.5 allowed attackers to inject arbitrary HTTP headers that persisted across all application requests, potentially enabling authentication bypasses and man-in-the-middle attacks.
-
The
__proto__property is the primary attack vector for prototype pollution—any code that merges untrusted objects without filtering this property is vulnerable. -
Axios 1.18.0's fix implements strict configuration validation and secure proxy handling through updated dependencies, eliminating the attack surface entirely.
-
Configuration objects should always be filtered through an allowlist before being merged into request settings; never directly spread untrusted user input into Axios configuration.
-
Dependency updates matter: The upgrade also included
https-proxy-agent5.0.1 andfollow-redirects1.16.0, which provide additional layers of security for HTTP operations.
How Orbis AppSec Detected This
Source: Untrusted HTTP request configuration passed to axios.request() via package.json dependency specification
Sink: The request configuration merging logic in Axios 1.13.5 that accepts user-controlled objects without prototype pollution validation
Missing Control: No validation of the __proto__, constructor, or prototype properties; no allowlist filtering of acceptable configuration keys; unsafe object merging patterns
CWE: CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes and Properties)
Fix: Upgrade Axios to version 1.18.0, which implements strict input validation, adds https-proxy-agent 5.0.1 for secure proxy handling, and updates follow-redirects to 1.16.0 and proxy-from-env to 2.1.0.
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
Prototype pollution vulnerabilities in HTTP client libraries like Axios represent a critical risk because they can silently compromise the security of every request an application makes. The vulnerability in Axios 1.13.5 demonstrated how a single misconfiguration in object merging could create a persistent attack surface affecting the entire application.
The upgrade to Axios 1.18.0 provides immediate protection through improved validation and secure dependency management. However, the broader lesson is crucial: never trust untrusted input in configuration objects, always use allowlists when accepting user-controlled settings, and keep dependencies updated as security patches are released.
By understanding how this vulnerability worked and implementing the recommended prevention practices, developers can build more resilient applications and help protect their users from sophisticated header injection attacks. Regular dependency audits, static analysis integration, and a security-first approach to configuration handling are essential practices in modern application development.
References
- CWE-1321: Improperly Controlled Modification of Object Prototype Attributes and Properties
- OWASP: Prototype Pollution
- Axios Official Documentation - Request Config
- Semgrep Rule: Prototype Pollution Detection
- GitHub PR: fix: upgrade axios to 1.15.1, 0.31.1 (CVE-2026-42035)
- Node.js Security Best Practices
- npm: Axios Security Advisories