Crlf Injection in Adonisjs with Dynamodb
Crlf Injection in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when an attacker can inject carriage return (CR, \r) and line feed (\n) characters into a header or a value that is later reflected into HTTP responses. In AdonisJS, this commonly surfaces when user input from a request is passed into a DynamoDB client operation and later echoed back in headers, cookies, or response fields. Although DynamoDB itself is a NoSQL database and does not interpret CR/LF, the risk arises when the data stored in or retrieved from DynamoDB is used by AdonisJS to construct HTTP messages, set cookies, or drive server-side redirects.
For example, an attacker might supply a name parameter containing example.com\r\nSet-Cookie: auth=attacker. If AdonisJS uses this value to build a redirect or a cookie without sanitization, the injected CRLF can split the response and inject a new header. DynamoDB may store this raw payload, and later reads from DynamoDB can re-introduce the malicious content into HTTP context, enabling session fixation or header manipulation. This becomes especially dangerous when combined with unsafe logging or error messages that reflect DynamoDB-stored values back to the client, as newlines can break formatting and allow early injection points.
The 12 security checks in middleBrick run in parallel and include Input Validation and Data Exposure, which help surface places where CRLF characters in DynamoDB-stored data might reach response headers or cookies. Because the scan is unauthenticated and tests the public attack surface, it can identify endpoints where user-controlled data enters the AdonisJS layer, is written to DynamoDB, and later influences HTTP semantics without adequate sanitization.
Dynamodb-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on preventing CRLF characters from being interpreted as control characters when data from DynamoDB is used in HTTP constructs. Always validate and sanitize any user input before it reaches DynamoDB, and never directly reflect stored values into headers, cookies, or redirects without strict allow-listing.
1. Input validation and sanitization
Use AdonisJS validation rules to reject or sanitize CR and LF characters in relevant fields. For string fields that must not contain newlines, enforce a regex that disallows \r and \n.
import { schema } from '@ioc:Adonis/Core/Validator'
const userSchema = schema.create({
username: schema.string({}, [rules.regex({ pattern: /^[^\r\n]+$/ })], 'Username must not contain line breaks'),
email: schema.string({}, [rules.email(), rules.regex({ pattern: /^[^\r\n]+$/ })], 'Email must not contain line breaks'),
})
export default class UsersController {
public async store({ request, response) {
const payload = await request.validate({ schema: userSchema })
// safe to proceed: payload.username and payload.email contain no CR/LF
}
}
2. Safe DynamoDB interactions in AdonisJS
When storing or retrieving data from DynamoDB, ensure that values are sanitized before insertion and are treated as opaque data on retrieval. Below is a concrete example using the official AWS SDK for JavaScript v3 within an AdonisJS service.
import { DynamoDBClient, PutItemCommand, GetItemCommand } from '@aws-sdk/client-dynamodb'
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'
const client = new DynamoDBClient({ region: 'us-east-1' })
export class ProfileService {
async setProfile(userId: string, inputName: string) {
// Sanitize before sending to DynamoDB: remove CR/LF
const safeName = inputName.replace(/[\r\n]/g, '')
const params = {
TableName: 'profiles',
Item: marshall({
userId: { S: userId },
name: { S: safeName },
updatedAt: { S: new Date().toISOString() },
}),
}
await client.send(new PutItemCommand(params))
}
async getProfile(userId: string) {
const params = {
TableName: 'profiles',
Key: marshall({ userId: { S: userId } }),
}
const { Item } = await client.send(new GetItemCommand(params))
if (!Item) return null
const profile = unmarshall(Item)
// safe to use profile.name in non-header contexts; do not set cookies/headers directly with this value
return profile
}
}
3. Avoiding CRLF in HTTP constructs derived from DynamoDB
When using data from DynamoDB to set cookies, headers, or perform redirects, apply allow-listing or strict encoding. For cookies, use response.cookie with built-in encoding, and avoid concatenating raw strings that could contain \r or \n.
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class SessionsController {
public async login({ session, auth, response }: HttpContextContract) {
const user = await auth.authenticate()
// Example: do not directly inject user.displayName into a cookie without sanitization
const displayName = user.displayName.replace(/[\r\n]/g, '')
session.put('displayName', displayName)
// Use AdonisJS cookie helpers which handle encoding safely
response.cookie('display', displayName, { httpOnly: true, path: '/' })
return response.redirect().toRoute('home')
}
}
By combining robust input validation, safe marshalling/unmarshalling with the DynamoDB SDK, and careful handling when writing values into HTTP headers or cookies, the risk of CRLF Injection in an AdonisJS application backed by DynamoDB is substantially reduced.