HIGH out of bounds readexpressbearer tokens

Out Of Bounds Read in Express with Bearer Tokens

Out Of Bounds Read in Express with Bearer Tokens — how this specific combination creates or exposes the vulnerability

An Out Of Bounds Read occurs when an application reads memory beyond the intended allocation. In Express, this often arises through unchecked array or buffer indexing. When Bearer Tokens are involved—typically passed via the Authorization header as Authorization: Bearer <token>—the token value may be parsed, split, or indexed without validating length or boundaries. If the code uses the token to derive an array index (e.g., selecting a user role from a list based on a numeric claim or position), an attacker-controlled token can supply an out-of-range value, leading to unintended memory reads. In JavaScript runtime terms, this can expose sensitive data from adjacent memory-like structures such as Buffer objects, typed arrays, or strings, potentially leaking private parts of tokens or other request-scoped data.

Consider an Express route that decodes a JWT Bearer token and uses a numeric payload field as an array index to select permissions:

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

app.get('/resource', (req, res) => {
  const auth = req.headers.authorization || '';
  const token = auth.startsWith('Bearer ') ? auth.slice(7) : '';
  try {
    const payload = jwt.decode(token, { complete: false });
    // Assume payload.index is controlled by the token
    const permissions = ['read', 'write', 'admin'];
    const role = permissions[payload.index]; // Out Of Bounds Read if index < 0 or >= 3
    res.json({ role });
  } catch (err) {
    res.status(401).json({ error: 'invalid_token' });
  }
});

app.listen(3000);

Here, the Bearer Token carries an attacker-controlled index. If the token provides index = 999, the read permissions[999] steps outside the array bounds. In some JavaScript engine implementations, this can return an undefined value or, under rare conditions, expose adjacent data, effectively creating an Out Of Bounds Read. An attacker might craft a token with an extreme numeric index to probe for information leakage, such as other request-scoped variables or internal strings, especially if the runtime does not consistently enforce bounds.

Another scenario involves Buffer-based token handling. If an Express app uses the token to initialize or slice a Buffer without verifying length, an oversized token can cause reads beyond the Buffer’s allocated memory:

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

app.get('/token-buffer', (req, res) => {
  const auth = req.headers.authorization || '';
  const token = auth.startsWith('Bearer ') ? auth.slice(7) : '';
  const tokenBuffer = Buffer.from(token);
  // Assume token length is attacker-controlled
  const byte = tokenBuffer[tokenBuffer.length]; // Out Of Bounds Read
  res.json({ byte });
});

app.listen(3000);

Accessing tokenBuffer[tokenBuffer.length] reads one byte beyond the Buffer, which may return 0 or an adjacent byte depending on the runtime. Combined with a Bearer Token supplied by the attacker, this becomes a controllable Out Of Bounds Read vector. The risk is elevated when the token is long, contains binary-like data, or when the application trusts the token’s structure implicitly.

These patterns highlight that the vulnerability is not in Bearer Tokens per se, but in how Express code indexes or slices data derived from them without validating size or range. The token becomes the attacker’s chosen lever to influence memory access, making the combination of Express routing, Bearer Token parsing, and unchecked indexing particularly hazardous.

Bearer Tokens-Specific Remediation in Express — concrete code fixes

Remediation focuses on validating and sanitizing any data derived from the Bearer Token before using it as an index or buffer offset. Always treat token claims as untrusted input, even if they are signed.

1. Validate array indices against known bounds

Ensure numeric claims used for indexing are integers and fall within the valid range before accessing arrays:

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

app.get('/resource', (req, res) => {
  const auth = req.headers.authorization || '';
  const token = auth.startsWith('Bearer ') ? auth.slice(7) : '';
  try {
    const payload = jwt.decode(token, { complete: false });
    const permissions = ['read', 'write', 'admin'];
    const index = Number(payload.index);
    if (Number.isInteger(index) && index >= 0 && index < permissions.length) {
      const role = permissions[index];
      return res.json({ role });
    }
    res.status(400).json({ error: 'invalid_index' });
  } catch (err) {
    res.status(401).json({ error: 'invalid_token' });
  }
});

app.listen(3000);

This checks that the index is an integer and within bounds, preventing out-of-range reads regardless of the Bearer Token’s content.

2. Avoid using token-derived values as Buffer offsets without length checks

If you must use token data for buffer operations, clamp the offset to the Buffer length:

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

app.get('/token-buffer-safe', (req, res) => {
  const auth = req.headers.authorization || '';
  const token = auth.startsWith('Bearer ') ? auth.slice(7) : '';
  const tokenBuffer = Buffer.from(token);
  // Use a safe offset derived from token length, but capped
  const offset = Math.min(Number(token.length), tokenBuffer.length - 1);
  const byte = tokenBuffer[offset]; // Guaranteed in-bounds
  res.json({ byte });
});

app.listen(3000);

By capping the offset to tokenBuffer.length - 1, the read stays within the Buffer, eliminating the out-of-bounds condition.

3. Prefer claims over positional indexing where possible

Instead of using a numeric index derived from the token, encode the required role or permission directly as a claim (e.g., role) and validate it against a set of allowed values:

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

app.get('/resource', (req, res) => {
  const auth = req.headers.authorization || '';
  const token = auth.startsWith('Bearer ') ? auth.slice(7) : '';
  try {
    const payload = jwt.decode(token, { complete: false });
    const allowedRoles = new Set(['read', 'write', 'admin']);
    if (allowedRoles.has(payload.role)) {
      return res.json({ role: payload.role });
    }
    res.status(403).json({ error: 'insufficient_scope' });
  } catch (err) {
    res.status(401).json({ error: 'invalid_token' });
  }
});

app.listen(3000);

This approach removes the need for index-based access entirely, leveraging the Bearer Token’s claims in a validated, structured way.

Across these patterns, the Bearer Token remains a bearer of identity and claims, but Express code must treat its contents as hostile input when used in memory-sensitive operations. These fixes align with secure handling of authentication data and reduce the attack surface for Out Of Bounds Read scenarios.

Frequently Asked Questions

Can an attacker exploit an Out Of Bounds Read via a malformed Bearer Token even if the token is invalid?
Yes. Even an invalid or expired Bearer Token can influence runtime behavior if the code parses or indexes based on its structure before validation. Always validate and bound-check all token-derived data.
Does middleBrick detect Out Of Bounds Read risks in Express APIs that use Bearer Tokens?
middleBrick runs 12 security checks in parallel, including Input Validation and Unsafe Consumption, which can surface patterns that may lead to Out Of Bounds Read. For details, you can scan your API endpoint with the middlebrick CLI or Web Dashboard to see per-category findings and remediation guidance.