HIGH credential stuffingexpresshmac signatures

Credential Stuffing in Express with Hmac Signatures

Credential Stuffing in Express with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Credential stuffing is an automated attack in which attackers use large lists of breached username and password pairs to gain unauthorized access to user accounts. In Express applications that rely on HMAC signatures for request authentication, a common design pattern is to sign a stable set of identifiers—typically the user identifier and a timestamp—to prove identity and freshness without transmitting passwords on every request.

The vulnerability arises when the HMAC is computed over data that does not uniquely bind the request to a single, non-reusable context. For example, if an endpoint accepts a user ID and a timestamp and signs them with a shared secret, an attacker can replay a captured, valid HMAC with a different user ID by altering only the non-signature parts of the request. Because the signature itself does not include a per-request nonce or a tightly bound resource identifier, the server may incorrectly validate the request as legitimate. This is especially risky when rate limiting or IP-based restrictions are weak or absent, allowing attackers to automate credential stuffing at scale using stolen or guessed credentials.

Even when the server checks the timestamp window to prevent replay, attackers can probe many accounts within the allowed time window. If the Express route does not enforce per-identifier rate limits or does not track failed attempts independently of the signature validation logic, attackers can cycle through many credentials without tripping defenses. In addition, if logs or error messages reveal whether a user ID exists, attackers can further refine their lists, increasing the efficiency of the stuffing campaign.

Because middleBrick scans unauthenticated attack surfaces, such weaknesses in authentication flows can be detected as part of the Authentication and BOLA/IDOR checks, with findings tied to frameworks such as OWASP API Top 10. The scans do not modify or block traffic; they highlight areas where the request design allows credential enumeration or replay via HMAC-based authentication in Express.

Hmac Signatures-Specific Remediation in Express — concrete code fixes

To reduce the risk of credential stuffing when using HMAC signatures in Express, design signatures to bind the request to the intended resource, include a nonce or per-request unique value, and enforce strict validation order. The following patterns illustrate concrete fixes and secure code examples.

1. Include the resource identifier in the signature

Ensure the HMAC covers the user identifier, the intended resource (e.g., target user ID or account number), the timestamp, and a nonce. This prevents an attacker from swapping the target resource while keeping a valid signature.

const crypto = require('crypto');

function buildHmac(userId, targetId, timestamp, nonce, secret) {
  const payload = `${userId}:${targetId}:${timestamp}:${nonce}`;
  return crypto.createHmac('sha256', secret).update(payload).digest('hex');
}

// Example request construction on the client
const userId = 'u123';
const targetId = 'u123'; // must match the resource the request intends to act upon
const timestamp = Date.now().toString();
const nonce = require('uuid').v4();
const secret = process.env.HMAC_SECRET;
const signature = buildHmac(userId, targetId, timestamp, nonce, secret);

2. Validate resource ownership and signature on the server

On the server, recompute the HMAC using the provided user identifier, the resource identifier from the request path or body, the timestamp, and the nonce. Reject the request if any component does not match expectations or if the resource identifier differs from the authenticated user context.

app.post('/api/account/:targetId', (req, res) => {
  const { userId, timestamp, nonce, signature } = req.body;
  const targetId = req.params.targetId;

  // Enforce strict ownership: the authenticated user must own the targetId
  if (userId !== targetId) {
    return res.status(403).json({ error: 'forbidden' });
  }

  const expected = buildHmac(userId, targetId, timestamp, nonce, process.env.HMAC_SECRET);
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).json({ error: 'invalid signature' });
  }

  // Additional checks: timestamp window and nonce replay protection
  const now = Date.now();
  if (Math.abs(now - parseInt(timestamp, 10)) > 30000) {
    return res.status(400).json({ error: 'stale request' });
  }

  // Verify nonce has not been used before (e.g., using a short-lived cache)
  if (seenNonces.has(nonce)) {
    return res.status(400).json({ error: 'replay detected' });
  }
  seenNonces.add(nonce);

  res.json({ ok: true });
});

3. Apply per-identifier rate limiting and anti-automation controls

Complement HMAC validation with rate limiting scoped to the user or target identifier. This prevents attackers from cycling through many credentials even when they possess valid signatures for some accounts.

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

const accountLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each userId/targetId pair to 5 requests per window
  keyGenerator: (req) => {
    // scope by user and target when possible
    return `${req.body.userId}:${req.params.targetId}`;
  },
  standardHeaders: true,
  legacyHeaders: false,
});

app.use('/api/account/:targetId', accountLimiter);

By combining resource-bound HMAC computation, strict ownership checks, replay-resistant nonces, timestamp windows, and per-identifier rate limiting, Express applications can significantly reduce the effectiveness of credential stuffing attacks that exploit HMAC-based authentication.

Frequently Asked Questions

Does including a nonce in the HMAC prevent replay attacks in Express?
Yes. Including a unique nonce in the HMAC payload and maintaining a short-lived allowlist of recently seen nonces ensures that even a captured, valid HMAC cannot be reused, effectively preventing replay attacks.
Can middleBrick detect weaknesses in HMAC-based authentication in Express?
Yes. middleBrick scans unauthenticated attack surfaces and can identify authentication design weaknesses such as missing resource binding, lack of replay protection, and insufficient rate limiting in Express-based APIs.