Prototype Pollution in Express with Basic Auth
Prototype Pollution in Express with Basic Auth — how this specific combination creates or exposes the vulnerability
Prototype pollution in Express applications that use HTTP Basic Authentication can arise when user-supplied input reaches object merge points and the runtime combines authentication handling with request processing. In this combination, an attacker can supply specially crafted property names such as __proto__, constructor.prototype, or constructor["prototype"] in query strings, headers, or JSON payloads. If the application or its dependencies merge these objects into configuration or authorization logic, the modified prototype can affect all objects inheriting from Object.prototype, leading to behavior changes that bypass intended access controls.
When Basic Authentication is involved, the server typically parses the Authorization header, decodes the base64 credentials, and splits them into username and password. If this parsing logic or subsequent route handling merges incoming data (e.g., parsed body or query parameters) into objects that influence permission checks, an attacker can pollute the prototype chain used to evaluate whether a user is authorized. For example, a pollution on a property used in an authorization guard could change the guard’s evaluation, effectively allowing actions that should require higher privileges. Because the scan tests unauthenticated attack surfaces, middleBrick checks such input validation and authorization flows, flagging places where unchecked input reaches sensitive runtime objects.
In the context of the 12 parallel security checks, this scenario intersects Authentication, BOLA/IDOR, Input Validation, and Property Authorization. An unauthenticated scan can detect whether the endpoint reflects or modifies objects derived from the prototype, and whether authentication headers are processed alongside mutable input. Real-world attack patterns mirror known CVEs where prototype pollution leads to privilege escalation or unintended application behavior. Remediation focuses on avoiding unsafe merges, validating and sanitizing input, and ensuring authorization logic does not depend on mutable prototype properties.
Basic Auth-Specific Remediation in Express — concrete code fixes
To secure Express routes that use HTTP Basic Authentication, avoid merging user input into objects that influence authorization and do not extend built-in prototypes. Parse credentials in isolation, validate them strictly, and keep authorization decisions based on verified values rather than dynamic properties derived from request data.
Secure Basic Authentication Example
const express = require('express');
const app = express();
// Middleware to parse and validate Basic Auth credentials
function basicAuth(req, res, next) {
const header = req.headers['authorization'];
if (!header || !header.startsWith('Basic ')) {
return res.status(401).json({ error: 'Unauthorized' });
}
const base64 = header.split(' ')[1];
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
const [username, password] = decoded.split(':');
// Do not merge username/password into shared objects or prototypes
if (username === 'admin' && password === 'S3cureP@ss') {
req.user = { username, role: 'admin' };
return next();
}
res.status(401).json({ error: 'Invalid credentials' });
}
app.use(basicAuth);
// Example route with explicit authorization checks
app.get('/admin', (req, res) => {
if (req.user && req.user.role === 'admin') {
return res.json({ message: 'Admin access granted' });
}
res.status(403).json({ error: 'Forbidden' });
});
app.listen(3000, () => console.log('Server running on port 3000'));
Avoiding Prototype Pollution with User Input
// Unsafe: merging user input into an object that may affect the prototype
// const config = { ...userProvidedObject };
// Safe: explicitly pick allowed fields and avoid prototype pollution
function sanitizeConfig(input) {
const allowed = ['timeout', 'retries'];
const sanitized = {};
for (const key of allowed) {
if (Object.prototype.hasOwnProperty.call(input, key)) {
sanitized[key] = input[key];
}
}
return sanitized;
}
app.post('/settings', (req, res) => {
const settings = sanitizeConfig(req.body);
// Use validated settings for runtime logic
res.json({ applied: settings });
});
These examples demonstrate how to handle Basic Authentication credentials without exposing prototype chains to pollution and how to validate incoming data before it influences authorization. By combining strict credential parsing with explicit allowlists, you reduce the risk of prototype-based authorization bypasses.
Frequently Asked Questions
How does middleBrick detect prototype pollution risks in unauthenticated scans?
__proto__ or constructor.prototype affect runtime objects, flagging findings that align with known attack vectors like OWASP API Top 10 and CWE-1321.