Auth Bypass in Adonisjs with Redis
Auth Bypass in Adonisjs with Redis — how this specific combination creates or exposes the vulnerability
When AdonisJS applications use Redis as a session store or cache backend, misconfigured session handling and cache assumptions can create an authentication bypass path. AdonisJS typically relies on signed, HTTP-only cookies managed by its session driver, but if developer code reads or writes authentication state directly to Redis without proper validation, an attacker can manipulate identifiers to escalate or bypass intended access controls.
For example, storing user roles or permissions in Redis keys derived from user-supplied input (e.g., userId from URL parameters or cookies) without server-side ownership checks enables IDOR-like conditions. If an API endpoint retrieves session data from Redis using an ID taken from an unverified source, an attacker can substitute another user’s key and obtain unauthorized data or actions. This is not a Redis flaw per se; it is a design issue where application logic trusts data stored in Redis more than the framework’s own session/cookie validation.
Common patterns that increase risk include:
- Using raw user IDs as Redis keys for cached objects without verifying that the authenticated user owns that ID.
- Storing authorization tokens or capabilities in Redis and retrieving them based on values supplied by the client.
- Relying on session identifiers that are predictable or not properly invalidated on logout, allowing session fixation or reuse.
In an API security scan with middleBrick, such issues may surface across multiple checks: Authorization (BOLA/IDOR), Input Validation, and Authentication. The scanner does not assume trust in server-side stores; it tests whether endpoints correctly enforce ownership and scope when backend data stores like Redis are involved. Remediation focuses on ensuring that any data retrieved from Redis is tied to the authenticated session and validated against access control rules before use.
Redis-Specific Remediation in Adonisjs — concrete code fixes
Secure Redis usage in AdonisJS requires strict separation between session management and application-level caching, and always tying Redis data to the authenticated user’s identity. Below are concrete patterns to reduce the risk of auth bypass.
1. Use AdonisJS sessions for identity, not raw Redis keys
Let the framework manage session identifiers. Do not expose internal Redis keys to the client or derive access logic directly from user-controlled IDs.
// config/session.ts
import { SessionConfig } from '@ioc:Adonis/Addons/Session'
const sessionConfig: SessionConfig = {
driver: 'redis',
redis: {
port: 6379,
host: '127.0.0.1',
password: process.env.REDIS_PASSWORD,
keyPrefix: 'sess:',
},
cookie: {
name: '__Host-adonis_session',
httpOnly: true,
secure: true,
sameSite: 'strict',
},
}
export default sessionConfig
2. Validate ownership before reading from Redis
When you must store user-specific data in Redis, include the authenticated user’s ID in the key and verify it on read. Never trust a userId from params or headers alone.
import { Redis } from '@ioc:Adonis/Addons/Redis'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class UserProfileController {
public async show({ params, auth, response }: HttpContextContract) {
const userId = auth.user?.id
const requestedId = Number(params.id)
if (!userId || userId !== requestedId) {
response.badRequest({ error: 'Unauthorized' })
return
}
const key = `user:profile:${userId}`
const cached = await Redis.get(key)
if (!cached) {
return response.status(404).send({ error: 'Not found' })
}
return response.ok(JSON.parse(cached))
}
}
3. Avoid storing access tokens or roles in Redis keyed by user input
Do not use Redis to hold authorization data that the client can influence. If caching is necessary, scope keys tightly and treat cached data as read-only copies, not sources of truth.
// Good: key scoped to authenticated user’s own data
const profileKey = `profile:own:${auth.user?.id}`
await Redis.put(profileKey, JSON.stringify(profileData), 'EX', 3600)
// Bad: key derived from request parameters
// const unsafeKey = `profile:${req.qs.userId}`
// await Redis.get(unsafeKey)
4. Rotate session identifiers on privilege changes
Regenerate the session after login, logout, or role changes to prevent session fixation when Redis is used as the session backend.
import { session } from '@ioc:Adonis/Core/Session'
public async login({ auth, session }) {
await auth.authenticate()
session.regenerate() // new session ID in Redis
session.flash({ notification: 'Logged in' })
return response.redirect().toRoute('dashboard')
}
5. Enforce server-side authorization on every Redis read
Even when data is stored in Redis, re-check permissions using the authenticated identity and a robust policy layer, not just key patterns.
import { can } from '@ioc:Extra/policies'
public async update({ params, auth, response }) {
const record = await Redis.get(`record:${params.id}`)
if (!record) {
return response.notFound()
}
const user = auth.user
if (!can(user, 'update', JSON.parse(record))) {
return response.forbidden({ error: 'Forbidden' })
}
// proceed with update
}
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |