HIGH formula injectionexpresshmac signatures

Formula Injection in Express with Hmac Signatures

Formula Injection in Express with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Formula Injection occurs when an attacker can influence a calculation or expression that is later evaluated, often by injecting crafted data into parameters that affect pricing, redirects, or logic. In Express applications that use Hmac Signatures to validate requests, combining dynamic data from the client with signature verification can expose a vulnerability if the application uses the raw, attacker-controlled values in the data that is signed or in side-channels that affect signature interpretation.

Consider an Express endpoint that computes a total price using query parameters (e.g., price and quantity) and validates integrity with an Hmac Signature passed in a header. If the server constructs the signed string using the raw query values without strict normalization and type validation, an attacker can manipulate the numeric inputs to change the computed total while keeping the signature valid due to a weakness in how the server parses or uses those values. For example, supplying a negative value for price or a non-integer quantity can lead to unexpected behavior in the calculation, and if the signature is computed over a concatenation like price|quantity|timestamp without strict schema enforcement, the attacker may be able to inject formulas that produce incorrect financial outcomes.

Another vector specific to Hmac Signatures in Express is the inclusion of metadata or optional fields that are not consistently validated. If the server signs a subset of fields but later processes additional fields that were not part of the signed string, an attacker can inject parameters that alter control flow or data handling without invalidating the signature. This can lead to privilege escalation or unauthorized actions when the injected data affects authorization checks or business logic. For instance, an attacker might add a isAdmin parameter that the server mistakenly incorporates into processing even though it was not part of the Hmac calculation, effectively bypassing intended access controls.

SSRF and external data dependencies can further amplify Formula Injection risks when Hmac Signatures are used. If the Express app fetches external data (e.g., a product catalog) based on injected parameters and then signs or verifies a payload that references that data, an attacker can force the server to request maliciously crafted URLs. The signature may still verify if the attacker can predict or influence parts of the signed string, leading to unauthorized internal requests or data leakage. This pattern is common when integrations rely on dynamic URLs constructed from user input without strict allowlists.

To detect such issues, scanning tools examine how the server builds the data that is signed, whether input normalization and type coercion are applied consistently, and whether extra fields bypass signature checks. Inconsistent handling of numeric formats, missing schema validation, and over-permissive parsing in Express middleware can all contribute to Formula Injection vulnerabilities even when Hmac Signatures are in place.

Hmac Signatures-Specific Remediation in Express — concrete code fixes

Remediation focuses on strict input validation, canonical data serialization, and ensuring that the signed payload includes only intended, validated fields. Always parse and normalize inputs before using them in signature computation or business logic, and reject requests that contain unexpected or malformed data.

Secure Express Example with Hmac Signatures

The following example shows a hardened Express endpoint that validates query parameters, enforces types, and uses a canonical string for Hmac signing and verification. It uses Node.js built-in crypto and does not rely on optional or untrusted fields.

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

const SHARED_SECRET = process.env.HMAC_SECRET;

function validateAndParsePrice(value) {
  if (value === undefined || value === null) {
    throw new Error('Missing price');
  }
  const num = Number(value);
  if (!Number.isFinite(num) || num <= 0) {
    throw new Error('Invalid price');
  }
  // Keep two decimals to avoid floating-point issues
  return Math.round(num * 100) / 100;
}

function validateAndParseQuantity(value) {
  if (value === undefined || value === null) {
    throw new Error('Missing quantity');
  }
  const intVal = parseInt(value, 10);
  if (!Number.isInteger(intVal) || intVal <= 0) {
    throw new Error('Invalid quantity');
  }
  return intVal;
}

function buildSignedPayload(price, quantity, timestamp) {
  // Canonical, deterministic string; do not include untrusted metadata
  return `${price}|${quantity}|${timestamp}`;
}

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

app.get('/calculate', (req, res) => {
  try {
    const price = validateAndParsePrice(req.query.price);
    const quantity = validateAndParseQuantity(req.query.quantity);
    const timestamp = req.query.timestamp;

    if (!timestamp || typeof timestamp !== 'string') {
      return res.status(400).json({ error: 'Missing or invalid timestamp' });
    }

    const payload = buildSignedPayload(price, quantity, timestamp);
    const expectedSignature = computeHmac(payload);

    const providedSignature = req.headers['x-hmac-signature'];
    if (!providedSignature || !crypto.timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(providedSignature))) {
      return res.status(401).json({ error: 'Invalid signature' });
    }

    const total = price * quantity;
    res.json({ price, quantity, total, timestamp });
  } catch (err) {
    return res.status(400).json({ error: err.message });
  }
});

module.exports = app;

Key practices demonstrated:

  • Strict validation and type coercion: Convert and verify numeric inputs before use, rejecting malformed values.
  • Canonical serialization: Build the signed string from normalized, typed values to avoid injection through formatting differences.
  • Timing-safe comparison: Use crypto.timingSafeEqual to prevent signature comparison side channels.
  • Exclusion of untrusted fields: Do not incorporate additional query parameters or headers into the signed payload unless explicitly validated and included.

If your integration uses JSON bodies instead of query parameters, apply the same principles: parse and validate each field, enforce schemas (for example with a validation library), and only sign the canonical representation of the intended data. Avoid concatenating raw JSON strings for signing due to formatting variability; instead, serialize with a deterministic ordering (e.g., sorted keys) or sign critical fields individually with a consistent scheme.

Frequently Asked Questions

What should I do if my Express app already uses Hmac Signatures but still accepts extra query parameters?
Audit your request parsing and signature verification: ensure only intended, validated fields are included in the signed payload, and reject any unexpected parameters before processing business logic.
Can using a schema validation library help prevent Formula Injection with Hmac Signatures in Express?