Information Disclosure in Express with Basic Auth
Information Disclosure in Express with Basic Auth — how this specific combination creates or exposes the vulnerability
Express does not parse or validate HTTP Authorization headers by default. When Basic Auth is used without additional protections, credentials are sent in an RFC 7617–formatted header: Authorization: Basic base64(username:password). Because Base64 is reversible and not encrypted, this creates an information disclosure risk on any unencrypted channel. If TLS is absent or misconfigured, an on-path attacker can intercept the header and decode credentials easily. Even when TLS is present, other application-layer leaks can expose the same credentials: logs that print req.headers.authorization, error messages that include the header, or debug endpoints that return the full request object. Information disclosure in this context also covers the exposure of internal identifiers, data schemas, or stack traces that reveal whether Basic Auth is enforced, helping an attacker refine follow-up attacks such as credential brute-forcing or SSRF with authenticated requests.
Within a black-box scan like middleBrick, the tool checks whether the endpoint requires authentication and whether credentials are transmitted over an encrypted channel. It also inspects whether the application inadvertently leaks the Authorization header in responses, logs, or cross-origin configurations. For example, a missing Strict-Transport-Security header or a permissive CORS policy that exposes headers can compound the risk by allowing client-side scripts or third-party origins to observe or relay the header. Because Basic Auth credentials are static and often reused across services, disclosure can lead to lateral movement. The scan further correlates these findings with the Encryption check and Input Validation checks to highlight whether sensitive data exposure is mitigated by transport security and controlled output handling.
Another subtle disclosure vector involves HTTP method handling and error responses. An Express route that responds differently to OPTIONS or TRACE, or that returns detailed errors on authentication failures, can confirm the presence of Basic Auth and reveal patterns about the protected resources. Misconfigured helmet or absent security headers may further aid an attacker in inferring the runtime environment. The combination of Basic Auth with weak transport security or verbose error handling turns what might be a simple authentication mechanism into a source of actionable information leakage, which is why the scanner flags missing encryption and improper header handling as high-severity findings.
Basic Auth-Specific Remediation in Express — concrete code fixes
To reduce information disclosure when using Basic Auth in Express, enforce TLS for all traffic, avoid logging or echoing the Authorization header, and prefer a runtime secret store over static credentials. Below are concrete, secure patterns you can apply.
1. Enforce HTTPS and HSTS
Always terminate TLS at the edge or in your service. Use helmet to set HTTP Strict Transport Security and remove server-identifying headers.
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(helmet());
app.use(helmet.hsts({
maxAge: 31536000,
includeSubDomains: true,
preload: true
}));
// Redirect HTTP to HTTPS in environments where TLS is handled externally
app.use((req, res, next) => {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(301, 'https://' + req.headers.host + req.url);
}
next();
});
app.listen(443, () => console.log('HTTPS server running on port 443'));
2. Secure Basic Auth middleware without leaking credentials
Validate credentials safely and ensure the header is not echoed in responses or logs.
const basicAuth = require('express-basic-auth');
const users = {
'admin': process.env.ADMIN_PASS // store password in environment/secrets at runtime
};
app.use(basicAuth({
users: users,
challenge: true,
authorizeAsync: true,
// Prevent the header from being reflected in any response
setAuthorize: false,
// Do not log credentials; override the default logger
logFn: () => {}
}));
app.get('/secure', (req, res) => {
res.json({ message: 'Authenticated', user: req.auth?.user });
});
3. Avoid manual header parsing and reflection
Never manually read and forward authorization headers, and never include them in JSON error responses.
app.use((req, res, next) => {
// Dangerous: logging or echoing credentials
// console.log('Auth header:', req.headers.authorization);
next();
});
app.use((err, req, res, next) => {
// Ensure errors do not expose the Authorization header
res.status(err.status || 500).json({
error: err.message,
// Never include: auth: req.headers.authorization
});
});
4. Use environment variables and rotate credentials
Keep credentials out of source code. Load them at runtime and rotate regularly. Combine with IP allowlists where feasible to reduce exposure surface.
// Example: load from secure runtime secrets
const authUsers = {
user: process.env.BASIC_AUTH_USER,
pass: process.env.BASIC_AUTH_PASS
};
app.use(basicAuth({
users: authUsers,
challenge: true,
logFn: () => {}
}));
5. Complementary headers and scope limitation
Set security headers to reduce metadata leakage and scope Basic Auth to only the routes that need it.
app.use('/api/admin', basicAuth({ users: authUsers, challenge: true, logFn: () => {} }), (req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Referrer-Policy', 'no-referrer');
next();
}, adminHandler);Frequently Asked Questions
Can Basic Auth be used safely without TLS if I avoid logging the header?
What headers should I avoid exposing to reduce information disclosure while using Basic Auth?
Server and ensure sensitive routes are not discoverable through verbose error pages or CORS wildcarding.