Http Request Smuggling in Adonisjs with Firestore
Http Request Smuggling in Adonisjs with Firestore — how this specific combination creates or exposes the vulnerability
HTTP Request Smuggling arises when an API processes HTTP requests in a way that allows an attacker to smuggle a crafted request from one logical request boundary to another. In AdonisJS applications that use Google Cloud Firestore as the primary data store, this can occur when the framework’s HTTP layer (often via underlying Node.js servers and reverse proxies) does not enforce strict message boundary validation between requests, and Firestore operations are invoked based on parsed request inputs.
AdonisJS does not directly interact with Firestore’s wire protocol, but developers commonly use the @google-cloud/firestore SDK to perform database operations. If request parsing is inconsistent—for example, when the framework trusts frontend headers while a reverse proxy interprets the same headers differently—the boundary between requests can be blurred. A smuggled request may reach Firestore-related routes intended for authenticated or scoped operations, potentially causing unauthorized data reads or writes.
Consider a scenario where AdonisJS exposes an endpoint like /users/:userId/profile that internally fetches documents from a Firestore collection users. If the route relies on improperly validated Content-Length or Transfer-Encoding headers, an attacker can craft a request that smuggles an additional request intended to access or modify another user’s document. Because Firestore security rules are enforced at the document level, the smuggled request might bypass intended access controls if the backend does not re-validate user context for each operation.
Real-world patterns include using mismatched HTTP parsers (e.g., one middleware consuming part of the body while another expects the full body) or neglecting to reset stream state between requests in a keep-alive connection. In such cases, Firestore queries or mutations may execute with an assumed identity or project context, leading to data exposure or unauthorized modifications that are difficult to trace through application logs alone.
Because Firestore operations are stateful in terms of security rules but not inherently tied to HTTP session management, the risk is amplified when routes do not independently authenticate and authorize each request. The smuggling vector does not exploit Firestore itself but leverages inconsistent request handling in AdonisJS to reach Firestore endpoints with incorrect assumptions about the caller’s permissions.
Firestore-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on ensuring strict request parsing, validating all inputs before Firestore interactions, and isolating database operations per request. Below are concrete patterns and code examples for AdonisJS that reduce the risk of request smuggling when working with Firestore.
1. Enforce strict Content-Length and Transfer-Encoding handling
Configure the HTTP parser to reject ambiguous or conflicting headers. In AdonisJS, you can customize the request handling pipeline to validate headers before they reach route handlers.
// start/hooks.ts
import { Exception } from '@poppinss/utils'
export const requestValidator = {
async validateRequest(ctx) {
const req = ctx.request
const contentLength = req.header('content-length')
const transferEncoding = req.header('transfer-encoding')
// Reject requests with both headers; it's ambiguous
if (contentLength && transferEncoding) {
throw new Exception('Invalid headers: content-length and transfer-encoding cannot both be set', 400, 'E_INVALID_HEADERS')
}
// Optionally enforce chunked encoding only from trusted proxies
if (transferEncoding && !req.ip.startsWith('TRUSTED_PROXY_IP')) {
throw new Exception('Transfer-Encoding not allowed', 400, 'E_INVALID_HEADERS')
}
}
}
Then register this validator in your route middleware stack so it runs before Firestore operations are initiated.
2. Validate and sanitize inputs before Firestore reads/writes
Always treat request parameters as untrusted. Use AdonisJS schema validation to ensure that identifiers like userId conform to expected formats before using them in Firestore paths.
// validators/user.ts
import { schema } from '@ioc:Adonis/Core/Validator'
export const profileSchema = schema.create({
userId: schema.string({ trim: true, escape: true }, [schema.rules.uuid()]),
})
// controllers/UserController.ts
import { schemaValidator } from '@ioc:Adonis/Core/Validator'
import ProfileValidator from 'App/Validators/UserValidator'
import { collection, doc, getDoc } from 'firebase/firestore'
export default class UsersController {
public async profile({ request, response }: { request: any; response: any }) {
const payload = schemaValidator.validateSync('profile', request.all(), profileSchema)
const db = use('Firestore') // assume Firestore instance injected
const userRef = doc(collection(db, 'users'), payload.userId)
const snapshot = await getDoc(userRef)
if (!snapshot.exists()) {
return response.notFound({ message: 'Profile not found' })
}
return response.ok(snapshot.data())
}
}
This ensures that the userId is a valid UUID and prevents path manipulation attacks that could lead to unauthorized Firestore document access.
3. Isolate Firestore clients and reset state between requests
Avoid reusing request-scoped state that might be contaminated by a smuggled request. Create Firestore document references dynamically and avoid storing request-bound data in shared variables.
// services/firestoreService.ts
import { collection, doc, setDoc } from 'firebase/firestore'
export async function updateUserProfile(userId: string, data: any) {
// Always derive references from function parameters, not outer scope
const db = getFirestore()
const userRef = doc(collection(db, 'users'), userId)
await setDoc(userRef, data, { merge: true })
}
By constructing Firestore references inside functions using validated parameters, you reduce the risk that a smuggled request will reuse an incorrect reference derived from a previous request.
4. Apply Firestore security rules rigorously
Even with careful AdonisJS handling, enforce strict Firestore rules to ensure that each document access is individually authorized. Use request-time variables such as request.auth to validate ownership.
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
This ensures that even if a smuggling attempt reaches Firestore, the operation will be denied unless the authentication context matches the document path.
Frequently Asked Questions
Can middleBrick detect HTTP request smuggling in AdonisJS apps using Firestore?
middlebrick scan <url>), Web Dashboard, or GitHub Action to detect such issues early.