HIGH sql injectionadonisjsfirestore

Sql Injection in Adonisjs with Firestore

Sql Injection in Adonisjs with Firestore — how this specific combination creates or exposes the vulnerability

SQL Injection is commonly associated with relational databases, but when an AdonisJS application interacts with Google Cloud Firestore through custom query-building or unsafe data concatenation, injection-like behaviors can still manifest. Firestore itself is a NoSQL database and does not use SQL; however, risks arise when developers build queries by interpolating user input into strings or when using raw client input to control collection groups, field filters, or pagination parameters. In AdonisJS, which encourages structured query patterns via Lucid models, bypassing ORM protections and dropping to raw query methods can expose endpoints to injection-style attacks.

Consider an endpoint that dynamically filters Firestore collections based on request query parameters. If the route handler directly uses req.input('field') to construct a collection group query without validation or sanitization, an attacker could supply values designed to manipulate query behavior. For example, a malicious payload such as ' OR 1==1 // injected into a filter parameter may not break SQL, but it can distort query intent, expose unintended documents, or trigger excessive reads that contribute to a security risk finding such as BFLA or Property Authorization issues. The scanner’s checks for Unsafe Consumption and Input Validation are designed to detect these risky patterns in unauthenticated scans.

Another scenario involves dynamic collection or field names derived from user input. Firestore requires valid collection identifiers, but concatenating user-controlled strings to form collection paths can lead to unintended data access or information exposure. AdonisJS routes that call Firestore.collection(userSuppliedName) without strict allowlisting expose the unauthenticated attack surface, which middleBrick evaluates under its Black-box scanning methodology. Although Firestore enforces authentication at the service level, misconfigured rules combined with dynamic referencing can amplify exposure. The LLM/AI Security checks specifically look for system prompt leakage and prompt injection patterns; while not directly related to Firestore queries, they underscore the broader need to validate all external input before using it to influence backend behavior.

Additionally, ordering and pagination parameters that are not strictly typed or bounded can be abused. If an AdonisJS controller passes untrusted numeric offsets or sort keys directly into Firestore query modifiers, an attacker may probe data structures or infer dataset size through timing or result set variations. This aligns with BOLA/IDOR and Rate Limiting checks in middleBrick’s 12 parallel tests. Proper schema validation, strict type conversion, and allowlisted field names reduce the likelihood of injection-style outcomes, even in a NoSQL context.

Firestore-Specific Remediation in Adonisjs — concrete code fixes

To secure AdonisJS applications using Firestore, always prefer typed query construction and avoid dynamic string assembly for collection names, field paths, or filter values. Use environment-based configuration for project identifiers and enforce strict input validation before passing data to Firestore methods. The following examples illustrate secure patterns.

First, define a controlled mapping of allowed collections and fields. This allowlist approach ensures that user input cannot alter the structure of queries.

const ALLOWED_COLLECTIONS = ['users', 'products', 'orders'];
const ALLOWED_FIELDS = ['email', 'username', 'status', 'created_at'];

function getValidCollection(name) {
  if (!ALLOWED_COLLECTIONS.includes(name)) {
    throw new Error('Invalid collection');
  }
  return name;
}

function getValidField(name) {
  if (!ALLOWED_FIELDS.includes(name)) {
    throw new Error('Invalid field');
  }
  return name;
}

Next, construct queries using Firestore’s parameterized methods rather than string interpolation. The Firestore Node.js SDK supports direct field filtering with validated identifiers.

const { Firestore } = require('@google-cloud/firestore');
const firestore = new Firestore();

async function getFilteredUsers(collectionName, field, value) {
  const safeCollection = getValidCollection(collectionName);
  const safeField = getValidField(field);
  const collectionRef = firestore.collection(safeCollection);
  const snapshot = await collectionRef.where(safeField, '==', value).limit(100).get();
  const results = [];
  snapshot.forEach(doc => {
    results.push({ id: doc.id, ...doc.data() });
  });
  return results;
}

For dynamic sorting, map user-supplied sort keys to predefined safe values instead of passing raw strings.

function getSortField(requested) {
  const mapping = {
    email: 'email',
    created_at: 'created_at',
  };
  return mapping[requested] || 'created_at';
}

async function listEntities(collectionName, sortBy) {
  const safeCollection = getValidCollection(collectionName);
  const safeSort = getSortField(sortBy);
  const collectionRef = firestore.collection(safeCollection);
  const snapshot = await collectionRef.orderBy(safeSort, 'desc').get();
  return snapshot.docs.map(d => ({ id: d.id, ...d.data() }));
}

When using AdonisJS controllers, bind validated inputs to method parameters and avoid passing raw request bodies directly to Firestore calls. Leverage Joi or AdonisJS schema validation to enforce type and format constraints before any Firestore interaction.

const Joi = require('joi');

const filterSchema = Joi.object({
  collection: Joi.string().valid('users', 'products', 'orders').required(),
  field: Joi.string().valid('status', 'email', 'username').required(),
  value: Joi.string().max(255).required(),
});

async handle({ request }) {
  const { error, value } = filterSchema.validate(request.qs());
  if (error) {
    return { error: 'Invalid parameters' };
  }
  const data = await getFilteredUsers(value.collection, value.field, value.value);
  return data;
}

By combining strict allowlists, parameterized queries, and schema validation, you mitigate injection-style risks and align with secure coding practices. middleBrick’s checks for Input Validation, Unsafe Consumption, and Property Authorization help identify areas where such controls are missing.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Can Firestore injection allow attackers to read or modify data in an AdonisJS app?
Firestore does not use SQL, so traditional SQL injection is not applicable. However, unsafe construction of collection names, field filters, or dynamic queries can expose unintended data or distort access patterns, leading to excessive reads or unauthorized visibility. Proper input validation and allowlists prevent these risks.
Does middleBrick test for Firestore-specific injection risks in AdonisJS applications?
Yes, middleBrick runs checks for Unsafe Consumption, Input Validation, and Property Authorization during its 12 parallel security scans. While it does not execute code or modify data, it identifies patterns that could lead to injection-style vulnerabilities in API endpoints that interact with Firestore.