Session Fixation in Adonisjs with Dynamodb
Session Fixation in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability
Session fixation occurs when an application allows an attacker to force a user to use a known session identifier. In AdonisJS applications using DynamoDB as the session store, the risk arises from how session identifiers are created, stored, and validated. AdonisJS relies on session cookies to track authenticated state, and if the framework does not rotate or validate session identifiers after authentication, an attacker who knows or sets a cookie value can hijack the user’s session.
DynamoDB itself is a durable, low-latency key-value store commonly used for session persistence in AdonisJS via packages such as @ioc/Addons/Session with a DynamoDB driver. The vulnerability is not in DynamoDB but in the application’s session lifecycle: if an authenticated route does not issue a new session ID after login, an attacker can craft a request with a pre-set identifier (e.g., via URL or malicious site) and later use the same identifier to impersonate the victim. DynamoDB’s eventual consistency and partition-key design may also affect how quickly session updates propagate; if the write confirming the new session ID does not fully synchronize before subsequent reads, inconsistent validation behavior can occur across requests.
Attack scenarios include an attacker sending a victim a link like https://api.example.com/login?session_id=attacker123, or injecting a session identifier via a cross-site scripting vector that sets document.cookie. If AdonisJS accepts the provided identifier without regeneration, the victim’s authenticated session will share the same DynamoDB record keyed by that identifier. When the victim authenticates, the record is overwritten with valid credentials, allowing the attacker to reuse the same key. DynamoDB’s conditional writes and TTL settings may inadvertently retain stale or overwritten session entries, depending on how the adapter handles upserts and deletes, which can complicate detection.
Common misconfigurations include using a predictable session ID format, disabling regeneration on privilege changes, or improperly configuring the session driver’s table name and partition key. For example, if the partition key is based solely on the session ID without additional entropy or region context, hot partitions or race conditions may arise under high concurrency, making it easier for an attacker to guess or brute-force valid identifiers. MiddleBrick scans can detect missing session rotation and insecure session storage patterns by correlating authentication checks with runtime cookie behavior and DynamoDB access patterns.
To mitigate, ensure AdonisJS regenerates session identifiers after authentication and privilege changes, uses cryptographically random IDs, and validates session ownership on each request. Align session configuration with the principle of least privilege for the DynamoDB table, and monitor for anomalous write patterns that suggest fixation attempts. The framework’s session package should enforce secure cookie attributes and SameSite policies to reduce exposure.
Dynamodb-Specific Remediation in Adonisjs — concrete code fixes
Remediation centers on forcing session regeneration after login and ensuring DynamoDB-backed sessions use randomized identifiers and strict validation. Below is a minimal, secure configuration for AdonisJS with DynamoDB session storage that addresses fixation risks.
First, install the required session addon and DynamoDB adapter:
npm install @ioc/Addons/Session @adonisjs/redis @types/redis
Configure the session provider to use DynamoDB. In config/session.ts, set the driver and DynamoDB parameters:
import { Exception } from '@poppinss/utils'
import { HttpContextContract } from '@ioc/Adonis/Core/HttpContext'
export const sessionConfig = {
driver: 'dynamodb',
key: 'sid',
secure: true,
httpOnly: true,
sameSite: 'lax',
ttl: 24 * 60 * 60, // 24 hours
table: 'app_sessions',
partitionKey: 'sid',
region: 'us-east-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
}
Implement login logic that regenerates the session after successful authentication. In a controller handling POST /login:
import { HttpContextContract } from '@ioc/Adonis/Core/HttpContext'
import { schema } from '@ioc/Adonis/Core/Validator'
export default class SessionsController {
public async login({ request, auth, session }: HttpContextContract) {
const email = request.input('email')
const password = request.input('password')
const user = await User.findBy('email', email)
if (!user || !(await user.verifyPassword(password))) {
session.flash('error', 'Invalid credentials')
return response.badRequest({ error: 'Invalid credentials' })
}
// Regenerate session to prevent fixation
await session.regenerate()
// Log the user in; this will write to the DynamoDB session store
await auth.use('api').login(user)
session.put('userId', user.id)
return response.ok({ ok: true })
}
}
The session.regenerate() call creates a new session record in DynamoDB with a cryptographically random identifier and deletes the old one. Ensure your DynamoDB table uses a partition key that supports high cardinality; consider prefixing the sid with a hash or UUIDv4 to avoid predictability. Here is a sample DynamoDB document structure for a session entry:
{
"sid": "sess_3f9b8c2d-7a1e-4f6a-b8c2-1d9f0e8a7b6c",
"userId": "usr-12345",
"expiresAt": 1735689600,
"ip": "203.0.113.45",
"userAgent": "Mozilla/5.0 ..."
}
For additional safety, add middleware that validates session ownership on each request. In a provider’s boot method:
import { HttpContextContract } from '@ioc/Adonis/Core/HttpContext'
import Session from '@ioc/Adonis/Addons/Session'
export const handle = async (ctx: HttpContextContract, next: () => Promise) => {
const session = Session.get()
if (session.exists) {
const stored = await DynamoDB.get({ TableName: 'app_sessions', Key: { sid: session.id } }).promise()
if (!stored.Item || stored.Item.userId !== session.get('userId')) {
await session.delete()
return ctx.response.unauthorized('Session invalid')
}
}
await next()
}
Finally, enforce secure cookie attributes and monitor DynamoDB for unusual write patterns. MiddleBrick’s scans can surface missing regeneration steps and weak session storage configurations by cross-referencing authentication checks with runtime cookie and DynamoDB access behavior.