Broken Authentication

Broken Authentication in Node.js (Express) Guide [Mar 2026] [GHSA-v9xm-ffx2-7h35]

[Updated month year] Updated GHSA-v9xm-ffx2-7h35

Overview

Broken authentication can lead to account compromise, privilege escalation, and data breach when attackers bypass login checks or steal session credentials. In production, insecure cookie handling or tokens enable session hijacking and account takeover. No CVEs are referenced here since none were provided. In Node.js/Express, this vulnerability manifests through weak session management, JWT misuse, and missing protections around login flows. Common patterns include cookies without HttpOnly/Secure, predictable tokens, long-lived tokens, lack of token revocation, and no rate limiting to deter brute-force attempts. Remediation involves adopting secure defaults: use server-side sessions with HttpOnly cookies, verify and rotate tokens, enforce TLS, apply rate limiting, and store secrets securely. The code examples show vulnerable vs. fixed implementations to highlight the differences.

Code Fix Example

Node.js (Express) API Security Remediation
/* Vulnerable */
const express = require('express');
const cookieParser = require('cookie-parser');

const app = express();
app.use(express.json());
app.use(cookieParser());

// Insecure login: uses a static token in a non-HttpOnly cookie
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  if (username === 'admin' && password === 'password') {
    res.cookie('token', 'static-token-abc', { httpOnly: false, secure: false, sameSite: 'lax' });
    return res.json({ ok: true });
  }
  res.status(401).json({ ok: false });
});

app.get('/protected', (req, res) => {
  const token = req.cookies && req.cookies.token;
  if (token === 'static-token-abc') {
    return res.json({ secret: 'TOP-SECRET' });
  }
  res.status(401).json({ error: 'unauthorized' });
});

app.listen(3000, () => console.log('Vulnerable server listening on port 3000'));

/* Fixed */
const express2 = require('express');
const session = require('express-session');
const app2 = express();
app2.use(express.json());

app2.use(session({
  name: 'sessionId',
  secret: process.env.SESSION_SECRET || 's3cr3tK3y',
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    maxAge: 15 * 60 * 1000
  }
}));

app2.post('/login', (req, res) => {
  const { username, password } = req.body;
  if (username === 'admin' && password === 'password') {
    req.session.user = username;
    return res.json({ ok: true });
  }
  res.status(401).json({ ok: false });
});

app2.get('/protected', (req, res) => {
  if (req.session && req.session.user) {
    return res.json({ secret: 'TOP-SECRET' });
  }
  res.status(401).json({ error: 'unauthorized' });
});

app2.listen(3001, () => console.log('Fixed server listening on port 3001'));

CVE References

Choose which optional cookies to allow. You can change this any time.