Prompt Injection with Hmac Signatures
How Prompt Injection Manifests in Hmac Signatures
Prompt injection in HMAC-based authentication systems occurs when an attacker manipulates input data to trick the API into accepting malicious requests or leaking sensitive information. Unlike traditional prompt injection in LLMs, HMAC prompt injection exploits the cryptographic signing process itself.
The most common manifestation involves crafting request payloads that, when signed, create collisions or bypass authorization checks. For example, an attacker might manipulate array parameters or JSON structures to alter the canonical string that gets hashed:
// Malicious payload exploiting HMAC canonicalization
const maliciousPayload = {
'action': 'transfer',
'amount': 1000,
'account': 'victim-123',
// Array parameter that gets sorted differently during signing
'items': ['item1', 'item2', 'item3']
};
// Attacker crafts request where items array sorting affects signature
// If the server sorts items before signing but the client doesn't,
// the signatures won't match but the server might process the requestAnother attack vector involves time manipulation in HMAC signatures. Attackers can exploit clock skew between client and server to create valid signatures that appear legitimate but execute malicious actions:
// Time-based prompt injection
const now = new Date().getTime() - 3600000; // 1 hour in the past
const timestamp = Math.floor(now / 1000);
const message = `${HTTP_METHOD}${URL_PATH}${timestamp}${PAYLOAD}`;
const signature = crypto.createHmac('sha256', SECRET_KEY).update(message).digest('hex');
// This signature might be valid during server's clock skew window,
// allowing replay attacks or bypassing rate limitingHeader manipulation represents another critical attack surface. Attackers can inject additional headers or modify existing ones to change the canonical string without invalidating the signature:
// Header injection attack
const originalHeaders = {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
};
// Attacker adds headers that affect canonical string but not signature calculation
const maliciousHeaders = {
...originalHeaders,
'X-Forged-Header': 'malicious-value', // Changes canonical string
'X-Forwarded-For': '127.0.0.1' // Might bypass IP-based restrictions
};HMAC Signatures-Specific Detection
Detecting prompt injection in HMAC systems requires analyzing the cryptographic signing process and request handling. The first step is verifying canonical string construction consistency between client and server:
// Detection: Verify canonical string consistency
function detectCanonicalizationIssues(request) {
const clientCanonical = buildCanonicalString(request);
const serverCanonical = buildServerCanonicalString(request);
if (clientCanonical !== serverCanonical) {
console.warn('Canonical string mismatch detected - potential injection vector');
return true;
}
return false;
}Parameter tampering detection is crucial. Implement strict type checking and length validation for all parameters that contribute to the HMAC signature:
// Detection: Parameter tampering analysis
function analyzeParameters(payload) {
const suspiciousPatterns = [
/\$\{.*\}/, // Template injection
/eval\(.*\)/, // Code execution
/\.\./, // Path traversal
/[<>]/, // HTML injection
/\n\s*\n/ // Header injection
];
for (const [key, value] of Object.entries(payload)) {
if (typeof value === 'string' && suspiciousPatterns.some(pattern => pattern.test(value))) {
console.warn(`Suspicious parameter detected: ${key} = ${value}`);
return true;
}
}
return false;
}Time-based detection helps identify clock skew exploitation attempts. Monitor signature timestamps for anomalies:
// Detection: Time-based anomalies
function detectTimestampAnomalies(signatureTimestamp) {
const currentTime = Date.now() / 1000;
const maxSkew = 300; // 5 minutes
if (Math.abs(currentTime - signatureTimestamp) > maxSkew) {
console.warn('Timestamp outside acceptable skew range');
return true;
}
// Detect rapid succession of requests with similar timestamps
if (recentTimestamps.includes(signatureTimestamp)) {
console.warn('Potential replay attack detected');
return true;
}
recentTimestamps.push(signatureTimestamp);
if (recentTimestamps.length > 100) {
recentTimestamps.shift();
}
return false;
}HMAC Signatures-Specific Remediation
Remediation starts with implementing strict canonical string construction that eliminates ambiguity. Use deterministic ordering and explicit encoding:
// Remediation: Strict canonical string construction
function buildCanonicalString(request) {
const sortedKeys = Object.keys(request.payload).sort();
const canonicalParams = sortedKeys.map(key => {
const value = request.payload[key];
const encodedKey = encodeURIComponent(key);
const encodedValue = encodeURIComponent(String(value));
return `${encodedKey}=${encodedValue}`;
}).join('&');
const canonicalString = [
request.method.toUpperCase(),
request.path,
request.timestamp,
canonicalParams
].join('\n');
return canonicalString;
}Implement parameter type enforcement and strict validation to prevent injection through malformed data:
// Remediation: Parameter validation and type enforcement
function validateParameters(payload) {
const schema = {
action: { type: 'string', enum: ['transfer', 'query', 'update'] },
amount: { type: 'number', min: 0.01, max: 1000000 },
account: { type: 'string', pattern: '^[a-zA-Z0-9-]{3,20}$' },
items: { type: 'array', items: { type: 'string', pattern: '^[a-zA-Z0-9]{1,50}$' } }
};
for (const [key, rules] of Object.entries(schema)) {
const value = payload[key];
if (value === undefined) continue;
if (rules.type === 'string') {
if (typeof value !== 'string' || !rules.pattern.test(value)) {
throw new Error(`Invalid parameter: ${key}`);
}
} else if (rules.type === 'number') {
if (typeof value !== 'number' || value < rules.min || value > rules.max) {
throw new Error(`Invalid parameter: ${key}`);
}
} else if (rules.type === 'array') {
if (!Array.isArray(value)) {
throw new Error(`Invalid parameter: ${key}`);
}
for (const item of value) {
if (typeof item !== 'string' || !rules.items.pattern.test(item)) {
throw new Error(`Invalid array item in ${key}`);
}
}
}
}
}Implement replay protection and clock synchronization mechanisms:
// Remediation: Replay protection and clock synchronization
class ReplayProtection {
constructor() {
this.usedTimestamps = new Set();
this.maxWindow = 300; // 5 minutes
}
isReplay(timestamp) {
const current = Math.floor(Date.now() / 1000);
const windowStart = current - this.maxWindow;
// Remove old timestamps
this.usedTimestamps.forEach(ts => {
if (ts < windowStart) {
this.usedTimestamps.delete(ts);
}
});
// Check if timestamp already used
if (this.usedTimestamps.has(timestamp)) {
return true;
}
this.usedTimestamps.add(timestamp);
return false;
}
isClockSkewAcceptable(timestamp) {
const current = Math.floor(Date.now() / 1000);
const maxSkew = 300;
return Math.abs(current - timestamp) <= maxSkew;
}
}Related CWEs: llmSecurity
| CWE ID | Name | Severity |
|---|---|---|
| CWE-754 | Improper Check for Unusual or Exceptional Conditions | MEDIUM |