Container Escape in Express with Basic Auth
Container Escape in Express with Basic Auth
A container escape in an Express application that uses HTTP Basic Auth occurs when a vulnerability allows an attacker who has compromised the application inside a container to break out and interact with the host or other containers. The presence of Basic Auth affects the attack surface in two ways: it may be weak or misconfigured, and the way the app validates and uses credentials can interact with container networking and process isolation. If an input validation or SSRF flaw exists, an attacker can leverage Basic Auth–protected routes to smuggle credentials or pivot to management endpoints that expose host-level APIs.
For example, an Express route that parses user-controlled URLs and makes outbound requests can be abused via SSRF to reach the host’s Docker socket (/var/run/docker.sock) or the metadata service (169.254.169.254). If the SSRF target requires Basic Auth, the attacker may supply forged credentials to bypass IP-based allowlists that rely on client IP reputation. A second scenario involves credential leakage: if error messages or logs inadvertently expose Basic Auth credentials (e.g., via verbose stack traces or HTTP response headers), an attacker can reuse those credentials to call administrative endpoints that expose container runtime information or orchestrator APIs.
Exploitation often maps to the OWASP API Top 10 categories such as Broken Object Level Authorization (BOLA/IDOR) and Server-Side Request Forgery (SSRF), and real-world attack patterns include attempts to read Docker socket streams or abuse container orchestrator metadata endpoints. A scan with middleBrick would flag findings related to Input Validation and SSRF, and highlight how authentication mechanisms intersect with container networking to increase risk. The scanner’s LLM/AI Security checks also test whether prompts or outputs can leak container or orchestration details through endpoints that echo credentials or configuration.
Because middleBrick scans the unauthenticated attack surface in 5–15 seconds, it can surface risky endpoint behaviors—such as unauthenticated LLM endpoints or endpoints that reflect credentials—without requiring credentials. The tool cross-references OpenAPI/Swagger specs with runtime findings, making it effective at identifying mismatches where Basic Auth is documented but not consistently enforced across routes. If you use the middleBrick CLI (middlebrick scan <url>) or integrate the GitHub Action, you can detect these classes of issues in CI/CD before deploying to production.
Basic Auth-Specific Remediation in Express
Remediation focuses on eliminating hardcoded credentials, enforcing strict validation, and ensuring Basic Auth does not inadvertently aid container escape paths. Avoid embedding credentials in code or environment variables that are exposed in container images; instead, use runtime injection via secrets managed by the orchestrator. Always validate and sanitize any URLs or inputs used in HTTP requests, and enforce strict allowlists for destinations, especially when Basic Auth is required for upstream services.
Use middleware to normalize and verify credentials, and ensure that authentication failures do not leak sensitive information. Below are concrete Express examples that demonstrate secure handling of Basic Auth.
Insecure Example
const express = require('express');
const app = express();
const auth = require('basic-auth');
// Insecure: hardcoded credentials, no input validation
app.get('/admin', (req, res) => {
const user = auth(req);
if (user && user.name === 'admin' && user.pass === 'password123') {
res.send('Admin panel');
} else {
res.status(401).set('WWW-Authenticate', 'Basic realm="Admin"').end();
}
});
// Risky: SSRF-prone URL fetch with Basic Auth headers
app.get('/fetch', (req, res) => {
const { url } = req.query;
const authHeader = 'Basic ' + Buffer.from('admin:password123').toString('base64');
fetch(url, { headers: { Authorization: authHeader } })
.then(r => r.text())
.then(text => res.send(text))
.catch(err => res.status(500).send('Error'));
});
Secure Example
const express = require('express');
const app = express();
const auth = require('basic-auth');
const { parse } = require('url');
// Secure: credentials injected via secrets (simulated here), strict validation
const ALLOWED_HOSTS = new Set(['https://api.example.com']);
const safeGet = (targetUrl, credentials) => {
return new Promise((resolve, reject) => {
const parsed = parse(targetUrl, true);
if (!parsed.hostname) return reject(new Error('Invalid URL'));
if (!ALLOWED_HOSTS.has(parsed.protocol + '//' + parsed.host)) {
return reject(new Error('Host not allowed'));
}
// Use a secrets manager to obtain credentials at runtime instead of hardcoding
const token = credentials;
fetch(targetUrl, { headers: { Authorization: 'Basic ' + token } })
.then(r => r.ok ? r.text().then(resolve).catch(reject) : reject(new Error('Request failed')))
.catch(reject);
});
};
app.get('/fetch', async (req, res) => {
const user = auth(req);
if (!user || !user.name || !user.pass) {
return res.status(401).set('WWW-Authenticate', 'Basic realm="API"').end();
}
const token = Buffer.from(user.name + ':' + user.pass).toString('base64');
try {
const data = await safeGet(req.query.url, token);
res.set('Content-Type', 'text/plain').send(data);
} catch (err) {
res.status(400).send('Invalid request');
}
});
Operational Recommendations
- Never commit credentials to source control; use runtime secrets injection.
- Restrict outbound destinations with an explicit allowlist; reject non-HTTP(S) schemes and private IPs to mitigate SSRF and container escape paths.
- Log authentication failures without revealing credentials or stack traces.
- Rotate credentials regularly and prefer token-based or mutual TLS where feasible.
For teams managing many endpoints, middleBrick Pro ($499/mo) enables continuous monitoring and CI/CD integration, so changes to Basic Auth handling can be validated before deployment. The CLI (middlebrick scan <url>) provides quick feedback during development, and the GitHub Action can fail builds if risk scores exceed your configured threshold.