HIGH information disclosureexpresshmac signatures

Information Disclosure in Express with Hmac Signatures

Information Disclosure in Express with Hmac Signatures — how this specific combination creates or exposes the vulnerability

In Express, using HMAC signatures for request authentication is common, but improper implementation can lead to Information Disclosure. The vulnerability arises when signature comparison is performed in a way that leaks timing information or when sensitive data is inadvertently included in logs, error messages, or responses. For example, if a developer compares HMAC values using a standard equality check (==), an attacker can use timing attacks to learn partial signature information, gradually recovering the secret key.

Express applications often generate HMAC signatures over request components such as headers, query parameters, or payload to ensure integrity and authenticity. If the application echoes back request data—such as the computed signature or parts of the signed payload—in error responses or debug output, sensitive material may be exposed. This is especially risky when the signature or related metadata is included in HTTP responses, logs, or trace outputs that are accessible to unauthorized parties.

Another scenario involves poorly designed middleware that attaches signature-related data to the request object for downstream use. If this data is later serialized into JSON responses or logs without redaction, it can expose the signature or the logic used to generate it. For instance, logging req.headers['x-signature'] or including computed MAC values in API responses can directly disclose sensitive information that should remain internal.

Real-world attack patterns include intercepting responses that contain signature mismatches or debugging information. If an endpoint returns a 401 with details like 'Invalid signature: expected ', an attacker gains insight into how signatures are constructed. This knowledge can aid in crafting further attacks, such as bypassing integrity checks or learning the secret through adaptive chosen-message queries.

Compliance mappings such as OWASP API Top 10 2023 A01 (Broken Object Level Authorization) and A05 (Security Misconfiguration) are relevant when HMAC implementations leak data through verbose errors or improper handling of authenticated requests. PCI-DSS and SOC2 also require protection of cryptographic materials and prevention of information leakage during authentication.

Hmac Signatures-Specific Remediation in Express — concrete code fixes

To prevent Information Disclosure with HMAC signatures in Express, use constant-time comparison and avoid exposing signature material in responses or logs. Below are secure code examples demonstrating these practices.

Secure HMAC Verification with Constant-Time Comparison

Use Node.js's built-in crypto.timingSafeEqual to compare signatures in constant time, preventing timing attacks.

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

const SECRET = process.env.HMAC_SECRET; // store securely, e.g., Vault or env

function computeHmac(payload) {
  return crypto.createHmac('sha256', SECRET)
    .update(payload)
    .digest('hex');
}

app.use(express.json());

app.post('/webhook', (req, res) => {
  const receivedSignature = req.headers['x-signature'];
  if (!receivedSignature) {
    return res.status(400).json({ error: 'Missing signature' });
  }

  const payload = JSON.stringify(req.body);
  const expectedSignature = computeHmac(payload);

  const receivedBuffer = Buffer.from(receivedSignature, 'utf8');
  const expectedBuffer = Buffer.from(expectedSignature, 'utf8');

  // Ensure lengths match to avoid timing leaks via buffer length comparison
  if (receivedBuffer.length !== expectedBuffer.length) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const isValid = crypto.timingSafeEqual(receivedBuffer, expectedBuffer);
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the verified request
  res.json({ status: 'ok' });
});

Avoid Logging or Echoing Signature Material

Ensure middleware does not attach signature data to res.locals or request properties that might be serialized in error handlers or logs.

// BAD: Do not attach computed MAC to res.locals
app.use((req, res, next) => {
  const sig = computeHmac(JSON.stringify(req.body));
  res.locals.computedSignature = sig; // risk of inclusion in logs or responses
  next();
});

// GOOD: Compute and verify without persistent attachment
app.use((req, res, next) => {
  next();
});

Centralized Error Handling Without Details

Use a generic error handler that does not expose signature logic or internal details.

app.use((err, req, res, next) => {
  // Log full error internally for debugging
  console.error(err);
  // Return generic message to client
  res.status(500).json({ error: 'Internal server error' });
});

Secure Signature Generation for Outgoing Requests

When your service generates HMACs for outbound calls, avoid including the secret in logs or URLs.

function signRequest(body, secret) {
  return crypto.createHmac('sha256', secret)
    .update(JSON.stringify(body))
    .digest('hex');
}

// Example usage without logging the secret
const signature = signRequest(requestBody, process.env.HMAC_SECRET);
// Do NOT console.log({ secret: process.env.HMAC_SECRET, signature });

Environment and Configuration

Store the HMAC secret in environment variables or a secrets manager. Do not hardcode secrets in source files.

// .env.example (do not commit real values)
HMAC_SECRET=your-256-bit-base64-secret

Frequently Asked Questions

Why is constant-time comparison necessary for HMAC verification in Express?
Constant-time comparison prevents timing attacks where an attacker measures response times to infer how many bytes of the signature match, gradually recovering the secret.
Can I include HMAC-related fields in API responses for debugging?
No. Including computed signatures or related metadata in responses can disclose sensitive material and should be avoided in production.