Command Injection in Chi with Firestore
Command Injection in Chi with Firestore — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an attacker can influence shell commands executed by an application. In Chi (a minimalistic router for Node.js), routes often invoke helper functions that may interact with external services such as Google Cloud Firestore. If user-controlled input is passed to Firestore operations in an unsafe way and then forwarded to a shell or child process, the boundary between data and commands can blur, enabling injection.
Chi does not provide built-in sanitization for parameters captured from the request (e.g., :docId path parameters). When a handler constructs a command string to invoke a tool that reads or writes Firestore data—such as using gcloud CLI or a custom script—and embeds parameters directly into that string, an attacker can inject additional shell commands. For example, a docId like doc1; cat /etc/passwd could cause the handler to execute unintended commands if the input is concatenated without validation.
Even when Firestore itself is not directly exploitable via injection, the surrounding infrastructure can be. Consider a Chi route that exports Firestore documents to a local file for processing: firestore export gs://bucket --collection=users. If the export destination or a filter value is derived from user input and appended to the command, an attacker might manipulate the command flags or paths to read arbitrary files or achieve remote code execution. This is especially relevant when combined with insecure runtime configurations, overly permissive service accounts, or exposed administrative endpoints.
The LLM/AI Security checks in middleBrick highlight risks where AI-driven payloads might attempt to exploit such command boundaries, including prompt injection attempts that could trick an assistant into generating dangerous commands involving Firestore. Although middleBrick does not fix these issues, its findings help identify dangerous patterns—such as concatenating request parameters into shell commands—so developers can apply strict input validation and avoid unsafe process execution.
Real-world attack patterns mirror this: an API endpoint that builds a shell command using template strings with unsanitized input is vulnerable to classic injection techniques. Mitigations include avoiding shell execution entirely, using parameterized Firestore client calls, and applying rigorous input validation. middleBrick’s scan can detect endpoints that appear to construct commands with external input, flagging them for review even when the underlying Firestore usage is otherwise legitimate.
Firestore-Specific Remediation in Chi
To secure Chi routes that interact with Firestore, eliminate shell command construction and rely on the official Firestore client. Direct client methods do not invoke a shell and are not susceptible to command injection. If integration with tools like gcloud is unavoidable, use strict allowlists and avoid string interpolation.
Example of a vulnerable Chi handler that builds a shell command:
import { Router } from 'itty-router';
import { exec } from 'child_process';
const router = Router();
router.get('/export/:docId', (req) => {
const docId = req.params.docId;
// Dangerous: direct string concatenation
exec(`firestore export gs://my-bucket/${docId}`, (error, stdout, stderr) => {
// handle result
});
});
This pattern is unsafe because docId is inserted directly into the command string. An attacker could supply a value such as gs://other-bucket/../../etc/passwd or inject additional commands using shell metacharacters.
Secure alternative using the Firestore Admin SDK to read data without shell invocation:
import { initializeApp } from 'firebase-admin/app';
import { getFirestore, doc, getDoc } from 'firebase-admin/firestore';
import { Router } from 'itty-router';
initializeApp({
credential: /* service account */
});
const db = getFirestore();
const router = Router();
router.get('/doc/:docId', async (req) => {
const docId = req.params.docId;
// Basic allowlist validation for document ID
if (!/^[a-zA-Z0-9_-]{1,100}$/.test(docId)) {
return { status: 400, body: { error: 'invalid document ID' } };
}
const snapshot = await getDoc(doc(db, 'collectionName', docId));
if (!snapshot.exists()) {
return { status: 404, body: { error: 'not found' } };
}
return { status: 200, body: snapshot.data() };
});
This approach uses the Firestore client to fetch a document by ID, avoiding any shell interaction. The route includes a strict regex allowlist for docId, rejecting unexpected characters. For operations that traditionally might use exports or imports, prefer the Firestore Admin SDK methods or service account–based batch operations rather than invoking external commands.
When integration with external tooling is required, middleBrick’s scans can surface risky command-building patterns and help prioritize remediation. The CLI tool (middlebrick scan <url>) and GitHub Action enable automated detection of such issues in CI/CD, while the Web Dashboard tracks these findings over time. Even with these aids, remediation remains a developer responsibility—middleBrick reports and provides guidance but does not alter code.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |