HIGH xss cross site scriptingexpresshmac signatures

Xss Cross Site Scripting in Express with Hmac Signatures

Xss Cross Site Scripting in Express with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Cross-site scripting (XSS) in Express applications that use HMAC signatures can still occur when signed values are rendered in the browser without proper output encoding. HMAC signatures are typically used to ensure integrity and authenticity of data (e.g., a signed user ID in a cookie or a signed JSON Web Token). If the application trusts the signature and directly embeds associated data into HTML, JavaScript, or URL contexts without sanitization, an attacker can still inject malicious scripts. This commonly happens when an attacker-controlled payload is included in signed claims that are later rendered in the application’s response and treated as safe because the signature validates correctly.

Express applications often use signed cookies via cookie-parser with a secret to validate values. For example, a server might set a signed cookie containing a user display name and then render that name directly into an HTML template. If the display name includes <script>alert(1)</script>, and the server embeds it without escaping, the browser executes the script even though the cookie signature is valid. Similarly, APIs that return signed tokens and have client-side code interpret the payload without output encoding can lead to reflected or stored XSS when the token’s claims include unsanitized user input.

Another scenario involves template injection where an attacker can control part of the data used to render a template and the application signs that data to avoid tampering. Because the signature only guarantees integrity, not safety, the server must still enforce context-aware escaping. Failing to do so turns HMAC-based integrity into a false sense of security. The vulnerability aligns with OWASP API Top 10 A05:2023 — Security Misconfiguration, and can expose APIs to XSS via JSON injection or DOM-based XSS when the client processes signed data without sanitization.

SSRF and input validation checks within middleBrick do not automatically prevent XSS stemming from trusted signed data; they validate structure and access controls, not output context. Therefore, developers must treat signed data as untrusted in output contexts and apply appropriate encoding based on where the data is used (HTML body, attribute, JavaScript, or URL).

Hmac Signatures-Specific Remediation in Express — concrete code fixes

To remediate XSS when using HMAC signatures in Express, always encode data based on the output context and validate/sanitize inputs before signing or rendering. Below are concrete examples demonstrating secure handling.

Example 1: Signed cookie with safe HTML rendering

Use the cookie-parser with signed cookies and escape data in templates (using a template engine like EJS with escaping enabled by default).

const express = require('express');
const cookieParser = require('cookie-parser');

const app = express();
const SECRET = process.env.COOKIE_SECRET; // keep secret in env
app.use(cookieParser(SECRET));

app.get('/set', (req, res) => {
  // sign a safe representation of data
  const displayName = 'JaneDoe'; // ideally sanitized on input
  res.cookie('user', { name: displayName }, { signed: true, httpOnly: false });
  res.send('Cookie set');
});

app.get('/profile', (req, res) => {
  const user = req.signedCookies.user;
  if (!user) return res.status(401).send('Unauthorized');
  // Escape output for HTML context
  const escapedName = escapeHtml(user.name);
  res.send(`
Hello, ${escapedName}
`); }); function escapeHtml(str) { if (typeof str !== 'string') return str; return str.replace(/[&<>"']/g, (s) => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[s])); }

Example 2: Signed JSON response with context-aware encoding

If sending signed data to a client that will render it in JavaScript, do not embed directly into inline scripts. Instead, serve JSON via an API endpoint and fetch it securely, or encode for HTML attributes/JS strings.

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

const app = express();
const SECRET = process.env.HMAC_SECRET;

function signData(data) {
  const payload = JSON.stringify(data);
  const hmac = crypto.createHmac('sha256', SECRET);
  hmac.update(payload);
  return { payload, sig: hmac.digest('hex') };
}

function verifyData(payload, sig) {
  const hmac = crypto.createHmac('sha256', SECRET);
  hmac.update(payload);
  const expected = hmac.digest('hex');
  return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

app.get('/data', (req, res) => {
  const data = { username: 'alice', role: 'user' };
  const { payload, sig } = signData(data);
  res.json({ payload: JSON.parse(payload), sig });
});

app.post('/verify', express.json(), (req, res) => {
  const { payload, sig } = req.body;
  if (!verifyData(payload, sig)) {
    return res.status(400).send('Invalid signature');
  }
  const data = JSON.parse(payload);
  // Ensure safe usage in downstream contexts; do not eval or innerHTML
  res.send(`Received user: ${escapeHtml(data.username)}`);
});

function escapeHtml(str) {
  const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
  return String(str).replace(/[&<>"']/g, (ch) => map[ch]);
}

Best practices

  • Sign integrity, not safety: HMAC ensures data hasn’t been altered, not that it’s safe for a given output context.
  • Context-aware escaping: HTML body, HTML attribute, JavaScript string, and URL each require different escaping functions.
  • Validate and sanitize inputs early: Treat all user input as untrusted, even if it will be signed later.
  • Use HTTPOnly and Secure flags for sensitive signed cookies to reduce exposure.
  • Leverage middleBrick scans to detect XSS and related misconfigurations; treat findings as guidance to review output handling around signed data.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Does a valid HMAC signature guarantee that data is safe to render as HTML?
No. HMAC signatures guarantee integrity and authenticity, not safety. Always apply context-aware output encoding to prevent XSS, regardless of signature validity.
Can middleBrick detect XSS in endpoints that use HMAC signatures?
Yes. middleBrick scans the unauthenticated attack surface and can identify XSS and related misconfigurations; it does not, however, fix or block findings, it provides remediation guidance.