Cross Site Request Forgery in Adonisjs with Mongodb
Cross Site Request Forgery in Adonisjs with Mongodb — how this specific combination creates or exposes the vulnerability
Cross Site Request Forgery (CSRF) in an AdonisJS application using MongoDB can occur when state-changing requests rely on session-based authentication without anti-CSRF protections. AdonisJS does not enable CSRF protection by default for API routes; if routes are configured to accept cookies/sessions (for example, a web UI calling an AdonisJS endpoint that writes to MongoDB), an attacker can trick a logged-in user into executing unwanted requests.
Consider an AdonisJS route that updates a user’s profile and stores data in MongoDB via an ODM like Mongoose or the native MongoDB driver. If the route only checks authentication (e.g., validates a session cookie) but does not verify the request origin or include a synchronizer token, a malicious site can craft a form that submits to that route on behalf of the user. Example scenario: an authenticated user visits a malicious site while logged into your AdonisJS app; the malicious site sends a POST to /profile/update with updates that modify the user’s email or role in MongoDB. Because the request arrives with the user’s session cookie, AdonisJS may authorize it, and the MongoDB write proceeds.
Specific risk patterns with MongoDB in AdonisJS include:
- Unprotected PATCH/PUT endpoints that identify the user by session and apply updates directly to MongoDB without verifying intent.
- Use of unsafe methods like
findOneAndUpdatewith user-controlled filters that can be manipulated to change other users’ documents if ownership checks are missing. - Inadequate validation of referrer or origin headers, enabling forged requests from external sites.
Even if your app uses JSON-only API patterns, if cookies are used for session management and CSRF mitigations are not implemented, the combination of AdonisJS and MongoDB remains vulnerable. The framework does not automatically protect you from CSRF when sessions are in play; it is the developer’s responsibility to ensure appropriate defenses for state-changing operations that mutate MongoDB documents.
Mongodb-Specific Remediation in Adonisjs — concrete code fixes
To secure AdonisJS routes that interact with MongoDB, implement anti-CSRF measures and strict ownership checks. Below are concrete remediation steps with code examples.
1. Use anti-CSRF tokens for session-based routes
If your app uses session authentication for web routes, generate and validate CSRF tokens. AdonisJS provides built-in CSRF protection for web views; ensure it is enabled and tied to your forms.
// In start/routes.ts
import Route from '@ioc:Adonis/Core/Route'
Route.get('/profile', async ({ auth, view }) => {
const user = await auth.authenticate()
return view.render('profile', { csrfToken: request.csrfToken, user })
})
Route.post('/profile/update', async ({ request, auth, response }) => {
const user = await auth.authenticate()
// csrfToken is validated automatically for web middleware if enabled
const payload = request.only(['email', 'name'])
await User.findByIdAndUpdate(user.id, payload, { new: true })
response.redirect().toRoute('profile')
})
2. Enforce ownership checks with MongoDB queries
When updating documents in MongoDB, always scope updates to the authenticated user’s ID to prevent horizontal privilege escalation (BOLA/IDOR).
// Using native MongoDB driver in a controller
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { Db, ObjectId } from 'mongodb'
export default class ProfilesController {
constructor(protected db: Db) {}
public async updateProfile({ request, auth, response }: HttpContextContract) {
const user = await auth.authenticate()
const userId = new ObjectId(user.id)
const updates = request.only(['email', 'preferences'])
// Ensure the update only affects the authenticated user's document
const result = await this.db.collection('users').updateOne(
{ _id: userId },
{ $set: updates }
)
if (result.matchedCount === 0) {
throw new Error('Profile not found or access denied')
}
return response.redirect().back()
}
}
3. Validate Origin and Referer headers for state-changing requests
Add middleware that checks the Origin or Referer header for sensitive operations, rejecting requests that do not match your domain. This complements anti-CSRF tokens and helps block cross-origin forged requests.
// In start/kernel.ts or as a route middleware
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
const csrfProtection = async (ctx: HttpContextContract, next: () => Promise) => {
const allowedOrigin = 'https://yourapp.com'
const request = ctx.request
const origin = request.header('Origin')
const referer = request.header('Referer')
if (request.method() !== 'GET' && request.method() !== 'HEAD') {
if (origin !== allowedOrigin || (referer || '').indexOf('yourapp.com') === -1) {
throw new Error('Invalid request origin')
}
}
await next()
}
// Apply to specific routes
Route.post('/profile/update', 'ProfileController.updateProfile').middleware([csrfProtection])
4. Prefer stateless APIs where feasible
For APIs consumed by SPAs or mobile clients, use token-based authentication (e.g., JWT) instead of session cookies. This removes the reliance on cookies for state and inherently reduces CSRF risk. When using tokens, ensure proper storage and transmission via Authorization headers.
// Example: JWT validation middleware in AdonisJS
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { verify } from 'jsonwebtoken'
const jwtAuth = async (ctx: HttpContextContract, next: () => Promise) => {
const token = ctx.request.header('Authorization')?.replace('Bearer ', '')
if (!token) {
throw new Error('Unauthorized')
}
const payload = verify(token, process.env.JWT_SECRET!)
ctx.auth.user = payload as any
await next()
}