HIGH broken authenticationexpressbasic auth

Broken Authentication in Express with Basic Auth

Broken Authentication in Express with Basic Auth — how this specific combination creates or exposes the vulnerability

Basic Authentication over unencrypted HTTP is a common contributor to broken authentication in Express APIs. Because the credentials are base64‑encoded rather than encrypted, an attacker who can observe the network traffic can recover the username and password easily. If the server accepts any Authorization header without enforcing transport integrity, the authentication boundary collapses, and the attacker can reuse captured credentials across sessions.

Express does not enforce HTTPS by default, so developers must explicitly configure TLS termination at the load balancer or within the Node.js server. Without enforced HTTPS, Basic Auth credentials move in clear text across the network, directly violating confidentiality requirements for authentication. Even when HTTPS is used, other implementation flaws can still weaken authentication.

Another common issue is the lack of brute‑force protection. Basic Auth does not carry built‑in rate limiting, so an attacker can iterate over passwords or use credential lists without throttling. In Express, if route handlers validate credentials on each request but do not track failures or impose delays, automated tools can perform rapid credential testing. This expands the attack surface for credential stuffing and password spraying.

Improper credential storage compounds the risk. If the server stores passwords in plaintext or with weak hashing instead of a strong, salted algorithm like bcrypt, a data breach exposes valid credentials directly. MiddleBrick scans check whether the server leaks account enumeration details through timing differences or error messages, which can allow attackers to infer valid usernames even when authentication ultimately fails.

Finally, missing session invalidation and weak token handling can leave sessions active after logout or password changes. With Basic Auth, developers often rely on the browser’s built‑in credential manager, which may persist credentials beyond the intended lifecycle. Without explicit server‑side mechanisms to revoke sessions and enforce reauthentication for sensitive operations, the authentication state remains fragile and susceptible to misuse.

Basic Auth-Specific Remediation in Express — concrete code fixes

To harden Basic Auth in Express, enforce HTTPS, avoid plaintext storage, add rate limiting, and minimize information leakage. The following examples show secure patterns that align with these practices.

Enforce HTTPS and reject cleartext credentials

Ensure all API traffic uses TLS. In production, terminate TLS at the load balancer and instruct Express to trust the proxy. Reject requests that arrive over non‑secure channels.

const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();

const options = {
  key: fs.readFileSync('/path/to/private-key.pem'),
  cert: fs.readFileSync('/path/to/certificate.pem')
};

https.createServer(options, app).listen(443, () => {
  console.log('HTTPS server running on port 443');
});

Validate credentials securely and avoid timing leaks

Use a constant‑time comparison to prevent timing attacks. Store passwords with a strong adaptive hash like bcrypt, and compare the hashed value rather than the plaintext password.

const bcrypt = require('bcrypt');
const users = new Map(); // username -> { hash, salt }

async function verifyUser(username, password) {
  const record = users.get(username);
  if (!record) {
    // Use a dummy hash to keep timing consistent
    await bcrypt.compare(password, '$2b$10$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
    return false;
  }
  return bcrypt.compare(password, record.hash);
}

Add rate limiting and monitor failures

Apply per‑IP or per‑user rate limits to authentication endpoints. This reduces the effectiveness of brute‑force attacks without breaking legitimate usage.

const rateLimit = require('express-rate-limit');

const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each IP to 5 requests per windowMs on auth routes
  standardHeaders: true,
  legacyHeaders: false,
  message: { error: 'Too many attempts, try again later.' }
});

app.post('/login', authLimiter, async (req, res) => {
  const { username, password } = req.body;
  const ok = await verifyUser(username, password);
  if (!ok) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  res.json({ ok: true });
});

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Can Basic Auth ever be safe in Express?
Yes, only when used over enforced HTTPS with strong storage (bcrypt), rate limiting, constant‑time validation, and short credential lifetimes. Prefer token‑based mechanisms where possible.
How do findings map to compliance frameworks?
Findings related to broken authentication map to OWASP API Top 10 (2023) A07:2021, PCI‑DSS requirements around credential protection, and SOC2 controls for authentication integrity. MiddleBrick scans include these mappings in the report view available in the dashboard and CLI JSON output.