Header Injection in Adonisjs with Dynamodb
Header Injection in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability
Header injection occurs when untrusted input is placed into HTTP headers without validation or sanitization. In an AdonisJS application that interacts with DynamoDB, this typically arises when request parameters (e.g., query strings, headers, or body fields) are used to construct responses or influence DynamoDB operations that later affect response headers. For example, if an endpoint accepts a next or redirect_url parameter and uses it to set a Location header without validation, an attacker can inject arbitrary headers, potentially enabling HTTP response splitting or open redirects.
DynamoDB itself does not interpret headers, but the application layer in AdonisJS is responsible for safely constructing responses. If input flows from a DynamoDB item into an HTTP header (e.g., using item attributes to set custom headers), unsanitized attributes can lead to injection. Consider a scenario where a user profile stored in DynamoDB contains a display name that is later used in a header such as x-user-display. Without proper sanitization, newline characters in the display name could enable header injection. AdonisJS routes and controllers should treat any data entering the response pipeline—including data retrieved from DynamoDB—as untrusted.
The risk is compounded when developers use DynamoDB data to influence redirects or construct links. For instance, retrieving an item with a user-supplied redirect target and then setting a Location header without validation can lead to open redirects. Because DynamoDB stores schemaless data, an attribute might contain unexpected values (including newline or carriage return sequences) that, when passed to AdonisJS header-setting functions, bypass assumptions about content safety. This is not a DynamoDB flaw but an application-layer issue where AdonisJS improperly trusts data sourced from DynamoDB when building headers.
Dynamodb-Specific Remediation in Adonisjs — concrete code fixes
To prevent header injection when using DynamoDB in AdonisJS, sanitize and validate any data that may influence HTTP headers. Treat all DynamoDB attribute values as untrusted when they are used in response construction. Below are concrete patterns and code examples to implement safe handling.
1. Validate and sanitize header inputs
Never directly use DynamoDB item attributes for header values without normalization. Strip or encode newline characters and enforce strict allowlists where possible.
const sanitizeHeaderValue = (value) => {
if (typeof value !== 'string') return '';
// Remove newline and carriage return characters to prevent header splitting
return value.replace(/[\r\n]+/g, ' ').trim();
};
// In a controller, when setting a custom header from DynamoDB data
const userData = await dynamodb.get({ TableName: 'users', Key: { userId: '123' }});
const safeDisplayName = sanitizeHeaderValue(userData.Item?.displayName || '');
response.header('x-user-display', safeDisplayName);
2. Safe redirect handling with DynamoDB data
If using DynamoDB to store redirect targets, validate the URL strictly and avoid using raw user input or untrusted attributes for the Location header. Use a URL parsing library and ensure the redirect destination is within expected domains.
const validDomains = ['app.example.com', 'static.example.com'];
const isValidRedirect = (url) => {
try {
const parsed = new URL(url, 'http://localhost');
return validDomains.includes(parsed.hostname);
} catch {
return false;
}
};
// Example using DynamoDB item to decide redirect
const result = await dynamodb.get({ TableName: 'redirects', Key: { id: 'home' }});
const targetUrl = result.Item?.url;
if (targetUrl && isValidRedirect(targetUrl)) {
return response.redirect(targetUrl);
}
return response.redirect('/fallback');
3. Use AdonisJS built-in header utilities safely
AdonisJS provides helpers to manage headers; avoid manually concatenating header values that may originate from DynamoDB. When setting multiple headers, ensure each is independently sanitized.
// Good: using response.header with sanitized values
const item = await dynamodb.query({ ... }).promise();
item.Items.forEach((entry) => {
const safeValue = sanitizeHeaderValue(entry.meta || '');
response.header(`x-entry-meta-${entry.id}`, safeValue);
});
// Avoid: directly injecting unsanitized DynamoDB attributes
// response.header('x-meta', item.Item.untrustedMeta); // unsafe
4. Input validation at the route level
Use AdonisJS validation schemas to reject or normalize inputs that could lead to header injection, especially when those inputs influence DynamoDB queries or response headers.
import { schema } from '@ioc:Adonis/Core/Validator';
const headerInputSchema = schema.create({
redirect_url: schema.string.optional([
schema.url({}, { tldStrict: false }),
(_, value) => {
try {
const u = new URL(value);
if (!['app.example.com', 'static.example.com'].includes(u.hostname)) {
throw new Error('Invalid domain');
}
} catch {
throw 'Invalid redirect URL';
}
},
]),
});
// In controller
const payload = await validator.validate({ schema: headerInputSchema });
// Safe to use payload.redirect_url after validation