Container Escape in Adonisjs with Dynamodb
Container Escape in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability
A container escape in an AdonisJS application that interacts with DynamoDB typically arises from excessive IAM permissions assigned to the container or host-level process, combined with insecure deserialization or unsafe usage of DynamoDB data in the application layer. When AdonisJS runs inside a container, the runtime identity (e.g., an IAM role or access key) used to call DynamoDB may be overly permissive, allowing an attacker who achieves code execution to leverage those credentials for actions beyond the intended scope, such as reading other DynamoDB tables or invoking AWS services.
Specifically, if AdonisJS deserializes user-supplied input that is later used to construct DynamoDB requests (e.g., building a GetItem or Scan input object without strict validation), an attacker may inject malicious payloads that lead to Server-Side Request Forgery (SSRF) or unsafe consumption patterns. These patterns can expose metadata endpoints or trigger chained calls to other AWS services. Because DynamoDB responses may include sensitive metadata or be used to construct further requests, unchecked data flows from DynamoDB into templates or serialization logic can amplify exposure, enabling container escape via host filesystem or network access when combined with container misconfiguration.
The risk is further heightened when container security boundaries are weak (e.g., running as root, mounting sensitive host paths) and the application trusts DynamoDB data without validation. For example, an attacker might manipulate a DynamoDB item attribute that AdonisJS uses to build dynamic queries or command templates, leading to unintended command execution on the host or container, effectively breaking container isolation.
Dynamodb-Specific Remediation in Adonisjs — concrete code fixes
To mitigate container escape risks in AdonisJS when using DynamoDB, apply strict input validation, least-privilege IAM, and safe data handling. Below are concrete code examples using the AWS SDK for JavaScript v3 within an AdonisJS controller.
1. Validate and sanitize DynamoDB inputs
Always validate keys and values before constructing DynamoDB requests. Use an explicit schema to ensure only expected types and formats are accepted.
import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall } from "@aws-sdk/util-dynamodb";
import { schema, rules } from "@ioc:Adonis/Core/Validator";
const ItemSchema = schema.create({
tableName: [rules.safeEnum(["users", "products"])],
key: schema.object({
id: schema.string([rules.minLength(1), rules.maxLength(64)])
})
});
export default class ItemsController {
private readonly client = new DynamoDBClient({});
public async show({ request, response }) {
const payload = request.validate({ schema: ItemSchema });
const command = new GetItemCommand({
TableName: payload.tableName,
Key: marshall(payload.key)
});
const data = await this.client.send(command);
return response.ok(data.Item ? unmarshall(data.Item) : null);
}
}
2. Apply least-privilege IAM for container roles
Ensure the container’s IAM role grants only the required DynamoDB actions on specific resources. Avoid wildcard permissions.
# Example IAM policy snippet (not code, but policy guidance):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:Query"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/MyAppTable"
}
]
}
3. Avoid unsafe consumption of DynamoDB output
Do not directly pass DynamoDB item attributes into command construction or templates. Treat all DynamoDB data as untrusted.
import { unmarshall } from "@aws-sdk/util-dynamodb";
// Unsafe: using raw item to build a command or eval-like behavior
// const userCommand = item.UserCommand; // DO NOT DO THIS
// Safe: explicit extraction with validation
const item = { /* DynamoDB item */ };
const username = item.username?.S;
if (typeof username !== "string" || username.length > 128) {
throw new Error("Invalid username");
}
// Proceed with safe usage
4. Disable container-level privilege escalation
Run containers as non-root and avoid mounting sensitive host paths. Combine with DynamoDB client configuration that does not rely on instance metadata fallback if not needed.
const client = new DynamoDBClient({
region: "us-east-1",
// Avoid fallback to EC2/IMDS in containers unless explicitly required and secured
useHttp2: true,
requestHandler: {
// custom handler that does not rely on insecure metadata chains
}
});