Integrity Failures in Adonisjs with Firestore
Integrity Failures in Adonisjs with Firestore — how this specific combination creates or exposes the vulnerability
Integrity failures occur when an application fails to enforce data validity and trust boundaries between untrusted input and trusted internal state. In the combination of AdonisJS and Cloud Firestore, these failures typically arise at the intersection of framework-level request handling and Firestore’s schemaless, permission-driven data model. AdonisJS provides request validation and sanitization utilities, but if these are not applied consistently before Firestore operations, invalid or malicious data can be written directly to the database.
Because Firestore does not enforce a rigid schema at the database level, it is up to the application to guarantee data integrity. In AdonisJS, developers might rely on route-level validation (e.g., using the built-in validator or Joi-like schemas) without extending those checks to all write paths, such as background jobs or webhook handlers. This inconsistency creates an integrity failure surface where malformed or unexpected data types, missing required fields, or improperly sanitized strings (e.g., numeric IDs stored as strings) can be persisted.
Another common pattern is directly passing request query parameters or body fields into Firestore queries without normalization. For example, using a user-supplied id parameter to construct a Firestore document reference without verifying its format or ownership can lead to Insecure Direct Object References (IDOR) or Broken Object Level Authorization (BOLA), which are integrity violations. Additionally, Firestore security rules are not a substitute for application-level integrity checks; rules can permit a write while the resulting document violates business logic invariants (e.g., a status field containing an unexpected value).
AdonisJS middleware pipelines can inadvertently bypass integrity checks when developers place authentication or rate limiting middlewares before validation, allowing unchecked data to reach Firestore in certain edge cases. Furthermore, Firestore’s support for nested objects and arrays can amplify integrity issues if AdonisJS validation does not deeply validate nested structures, leading to partially trusted data being stored. Real-world attack patterns such as injection of malformed JSON, unexpected type coercion, or manipulation of array indices can exploit these gaps.
The LLM/AI Security checks in middleBrick are particularly relevant here because they detect system prompt leakage and jailbreak attempts that could be used to manipulate an AI-assisted API layer interacting with Firestore. If an AdonisJS API exposes endpoints that influence Firestore document generation or retrieval based on LLM outputs, unchecked LLM responses may introduce integrity failures by injecting non-compliant or malicious data into the database.
Finally, the absence of continuous monitoring in development workflows means integrity regressions can be introduced without detection. middleBrick’s Pro plan supports continuous monitoring and CI/CD integration, which helps ensure that any changes to validation logic or Firestore interaction patterns do not reintroduce integrity failures.
Firestore-Specific Remediation in Adonisjs — concrete code fixes
Remediation centers on enforcing strict validation before any Firestore interaction and normalizing data to match expected formats. Always treat Firestore document fields as untrusted, even when they originate from your own application code.
1. Validate and sanitize all inputs before Firestore operations
Use AdonisJS’s validator to define strict schemas and ensure data integrity before writing to Firestore. For example, when creating a user profile document, validate and cast fields explicitly:
// resources/validators/user_profile.ts
import { schema } from '@ioc:Adonis/Core/Validator'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class UserProfileValidator {
public schema = schema.create({
email: schema.string({ trim: true, normalize: true }, [rules.email()]),
age: schema.number([rules.range(0, 150)]),
tags: schema.array.optional(schema.string()),
})
public messages = {
'email.email': 'Email must be a valid email address',
'age.range': 'Age must be between 0 and 150',
}
}
// In a controller
import UserProfileValidator from 'App/Validators/UserProfileValidator'
export async function createProfile({ request, auth }: HttpContextContract) {
const payload = await request.validate(UserProfileValidator)
const userId = auth.user?.id
// Safe Firestore write with validated and normalized data
await firestore.collection('users').doc(userId).set({
email: payload.email,
age: payload.age,
tags: payload.tags || [],
updatedAt: new Date(),
}, { merge: true })
return { message: 'Profile updated' }
}
2. Normalize IDs and enforce ownership before Firestore document access
Always normalize and verify document references to prevent BOLA/IDOR. Use Firestore’s built-in document IDs safely by validating their format and ensuring they belong to the requesting user:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { DocumentReference } from '@google-cloud/firestore'
export async function getDocument({ params, auth }: HttpContextContract) {
const docId = params.id
// Validate document ID format (e.g., prevent path traversal or malformed IDs)
if (!/^[a-zA-Z0-9_-]{1,100}$/.test(docId)) {
throw new Error('Invalid document identifier')
}
const docRef = firestore.doc(`users/${auth.user?.id}/documents/${docId}`) as DocumentReference
const snapshot = await docRef.get()
if (!snapshot.exists) {
throw new Error('Document not found')
}
// Ensure the document is owned by the requesting user by checking parent path
const parentCollection = docRef.parent.parent?.id // 'users/{uid}'
if (parentCollection !== auth.user?.id) {
throw new Error('Unauthorized access')
}
return snapshot.data()
}
3. Enforce integrity with Firestore security rules and application logic
While security rules are not a replacement for application validation, they should complement integrity checks. Combine Firestore rules with AdonisJS validation to ensure data integrity:
// Firestore security rule example (conceptual)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/documents/{documentId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId
&& request.resource.data.keys().hasAll(['title', 'content'])
&& request.resource.data.title is string
&& request.resource.data.content is string
&& request.resource.data.title.size() > 0
&& request.resource.data.content.size() > 0;
}
}
}
In your AdonisJS application, mirror critical rule conditions in validators to catch errors early. For instance, if Firestore rules require a non-empty title, your validator should also enforce this, providing consistent integrity guarantees across client and server.
When integrating with AI tooling via the MCP Server, ensure that any AI-generated Firestore operations are validated against the same strict schemas. middleBrick’s LLM Security checks can help detect prompt injection attempts that might try to bypass integrity controls and inject invalid data into Firestore documents.
Finally, adopt continuous monitoring using middleBrick’s dashboard or Pro plan to track integrity-related findings over time. This ensures that changes to Firestore data structures or AdonisJS validation logic do not introduce regressions that could compromise data integrity.