HIGH race conditionexpressbasic auth

Race Condition in Express with Basic Auth

Race Condition in Express with Basic Auth — how this specific combination creates or exposes the vulnerability

A race condition in an Express API using HTTP Basic Auth occurs when the server’s authentication state and the request’s authorization credentials are not handled atomically, allowing an attacker to change credentials between the time the server checks them and the time it uses them. This can expose privileged behavior or data in endpoints that appear to be protected by Basic Auth but rely on non-atomic checks or shared mutable state.

Consider an Express route that first verifies a username and password, then retrieves or updates a user-specific resource. If the server performs the credential check and later performs an authorization check (for example, deciding what resource ID to allow access to) without tying the two together in a single, atomic operation, an attacker can race the request. An attacker can send parallel requests with different credentials while another request is in flight, potentially causing the server to use the wrong authorization context. For example, an endpoint like /api/users/:id might read the token or session, then look up the user by ID. If the ID is derived from data that can be influenced after authentication, or if the server caches credentials in an unsafe way, a concurrent request can change the effective identity used for the authorization decision.

In a black-box scan, such patterns can be detected when endpoints that return different data for the same path under different credentials show inconsistent timing or response differences when attacked with parallel requests. The scan’s Authentication and BOLA/IDOR checks can surface endpoints where Basic Auth is present but authorization is not safely bound to the authenticated identity. In the context of LLM/AI Security, an attacker might also attempt prompt injection to manipulate server-side logic that decides which user context to use, compounding the risk by changing server behavior mid-request.

Real-world attack patterns that map to this include scenarios where an application fails to bind session or token state to each request atomically, enabling an attacker to exploit timing differences. While this is not a direct implementation flaw in Basic Auth itself, it is a design flaw in how the application uses credentials and handles concurrency. The OWASP API Top 10 category API1:2023 Broken Object Level Authorization is relevant here, and such issues can also intersect with compliance frameworks when access controls are not reliably enforced.

Basic Auth-Specific Remediation in Express — concrete code fixes

To prevent race conditions when using Basic Auth in Express, ensure authentication and authorization are performed as a single, atomic operation and avoid storing mutable authentication state that can be changed by concurrent requests. Always validate credentials and derive the allowed scope or resource identifiers in one step, and use immutable identifiers for the authenticated identity.

Example of an unsafe pattern that can lead to race conditions:

// Unsafe: authentication and authorization are separate steps
app.get('/api/users/:id', (req, res) => {
  const auth = req.headers.authorization;
  if (!auth) return res.status(401).send('Unauthorized');
  const [user] = atob(auth.split(' ')[1]).split(':');
  // Race: user identity verified, but ID is taken from request parameter
  getUserById(req.params.id).then(resource => {
    if (!resource) return res.status(404).send('Not found');
    res.json(resource);
  });
});

An attacker can race this endpoint by sending concurrent requests with different credentials and different IDs, potentially accessing resources they should not see if the server does not bind the authenticated user to the resource ID atomically.

Recommended safe pattern that binds identity to authorization in a single step:

// Safe: authenticate and authorize together, using a stable identifier
app.get('/api/users/:id', (req, res) => {
  const auth = req.headers.authorization;
  if (!auth) return res.status(401).send('Unauthorized');
  const decoded = atob(auth.split(' ')[1]).split(':');
  const [username, password] = decoded;
  // Authenticate and derive user record atomically
  return authenticateAndAuthorize(username, password, req.params.id)
    .then(resource => {
      if (!resource) return res.status(403).send('Forbidden');
      res.json(resource);
    })
    .catch(() => res.status(401).send('Unauthorized'));
});

function authenticateAndAuthorize(username, password, targetId) {
  // Perform lookup and check in a single logical operation
  return getUserByCredentials(username, password).then(user => {
    if (!user) throw new Error('Invalid credentials');
    // Ensure the user is allowed to access the specific target ID
    if (!user.resources.includes(targetId)) throw new Error('Not authorized');
    return getResource(targetId);
  });
}

This pattern ensures that the identity used for authorization is derived together with the access decision, reducing the window for race conditions. In automated scans, endpoints that follow this pattern show consistent behavior across parallel requests with different credentials. If you use an OpenAPI/Swagger spec, ensure the spec defines security schemes for Basic Auth and that paths requiring authentication are explicitly declared, enabling cross-referencing of spec definitions with runtime findings.

Additional recommendations include avoiding caching of authentication state in shared variables and ensuring that any token or credential validation routines are idempotent and free of shared mutable data. The middleBrick CLI can be used to scan endpoints from the terminal with middlebrick scan <url>, and the GitHub Action can add API security checks to your CI/CD pipeline to fail builds if risk scores drop below your chosen threshold. For deeper investigation in your development workflow, the MCP Server allows scanning APIs directly from AI coding assistants.

Frequently Asked Questions

Can race conditions happen even when Basic Auth credentials are correct?
Yes. Race conditions are about timing and concurrency, not about whether credentials are correct. If authorization decisions are not bound atomically to the authenticated identity, an attacker can exploit parallel requests to access resources they should not reach, even with valid credentials.
Does using HTTPS prevent race conditions in Basic Auth?
HTTPS protects credentials in transit from eavesdropping, but it does not prevent race conditions in server-side authorization logic. You still need to perform authentication and authorization as an atomic operation and avoid unsafe shared state.