Shellshock in Firestore
How Shellshock Manifests in Firestore
Shellshock vulnerabilities in Firestore contexts arise when user-controlled data flows through system() calls or similar command execution functions without proper sanitization. In Firestore applications, this typically occurs in two scenarios: server-side Cloud Functions processing Firestore triggers, and client-side applications that execute shell commands based on database values.
Consider a Cloud Function that processes document writes:
exports.processDocument = functions.firestore.document('users/{userId}').onCreate(async (snap, context) => {
const data = snap.data();
const command = `echo "User ${data.name} created at ${data.timestamp}"`;
const { exec } = require('child_process');
exec(command, (error, stdout, stderr) => {
console.log(stdout);
});
});The vulnerability appears when data.name contains malicious payloads like $(cat /etc/passwd) or ; rm -rf /. Firestore's flexible schema allows arbitrary field names and values, making it easy for attackers to craft documents that trigger command injection when processed.
Client-side manifestations are equally dangerous. A web application might execute system commands based on Firestore-stored configuration:
const doc = await db.collection('config').doc('system').get();
const config = doc.data();
const { exec } = require('child_process');
exec(config.command, (error, stdout, stderr) => {
console.log(stdout);
});If an attacker gains write access to the 'config' collection, they can store arbitrary shell commands. The attack surface expands when Firestore security rules are misconfigured, allowing unauthorized writes to critical collections.
Real-world patterns include:
- Using document IDs or field names directly in shell commands
- Processing user-uploaded files that contain command injection payloads
- Executing system commands based on array elements from Firestore documents
- Dynamic command construction using template literals with unvalidated data
The attack vectors are particularly insidious because Firestore's document-based structure allows attackers to target specific fields while leaving others intact, making detection harder.
Firestore-Specific Detection
Detecting Shellshock vulnerabilities in Firestore requires examining both the database structure and the application code that interacts with it. middleBrick's scanning approach for Firestore environments includes several specialized checks.
middleBrick scans for command execution patterns by analyzing:
- Cloud Functions that use
child_process.exec,execSync,spawn, or similar APIs - Template literals containing user data that flow to system commands
- Firestore security rules that allow write access to collections containing configuration data
- API endpoints that accept Firestore document IDs as parameters for command execution
The scanner specifically looks for patterns like:
const command = `echo "${userInput}"`;or:
exec(`ls ${path}`);middleBrick's Firestore-specific detection also examines:
- Collections with names suggesting configuration or system control
- Documents containing fields that could be interpreted as commands
- Security rules that grant write access to sensitive collections
- API endpoints that accept document references as parameters
Manual detection should focus on:
grep -r "exec(" . --include="*.js" --include="*.ts"
grep -r "spawn(" . --include="*.js" --include="*.ts"
grep -r "system(" . --include="*.js" --include="*.ts"
Look for template literals that concatenate user data:
const vulnerable = data.userInput;middleBrick provides detailed findings including:
| Finding Type | Risk Level | Common Location |
|---|---|---|
| Command Injection | Critical | Cloud Functions |
| Template Literal Injection | High | API Handlers |
| Security Rule Misconfiguration | High | Firestore Rules |
| Dynamic Command Construction | Critical | Background Workers |
The scanner also checks for indirect vulnerabilities where Firestore data flows through multiple transformation steps before command execution, making them harder to detect through manual code review.
Firestore-Specific Remediation
Remediating Shellshock vulnerabilities in Firestore applications requires a defense-in-depth approach. The primary strategies involve input validation, command sanitization, and architectural changes to eliminate the need for command execution.
Input Validation:
function sanitizeInput(input) {
// Remove shell metacharacters
return input.replace(/[;|&$`(){}]/g, '');
}
// Usage
const safeName = sanitizeInput(data.name);
const command = `echo "User ${safeName} created"`;
Command Parameterization:
const { exec } = require('child_process');
function safeExec(command, args) {
// Use array form to prevent shell interpretation
exec([command, ...args].join(' '), (error, stdout, stderr) => {
console.log(stdout);
});
}
// Instead of: exec(`echo "${unsafeData}"`)
// Use: safeExec('echo', [safeData]);
Firestore Security Rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /config/{docId} {
allow read: if request.auth != null;
allow write: if false; // Prevent unauthorized writes
}
match /users/{userId} {
allow create: if request.auth != null &&
request.resource.data.name.size() < 100;
}
}
}
Architectural Refactoring:
// Instead of executing shell commands, use native Node.js APIs
const fs = require('fs').promises;
async function processUserData(data) {
// Use file system APIs instead of shell commands
await fs.writeFile('/tmp/user.log', `User ${data.name} created`);
// Use database operations instead of system commands
await db.collection('audit').add({
action: 'user_created',
userId: data.id,
timestamp: new Date()
});
}
MiddleBrick's remediation guidance includes specific recommendations based on the vulnerability type:
- For command injection: Replace
exec()with parameterized APIs - For template literal injection: Implement strict input validation
- For security rule issues: Restrict write access to sensitive collections
- For dynamic command construction: Use configuration objects instead of string concatenation
Testing remediation involves:
// Test with malicious input
const maliciousInput = "$(whoami)";
const safeCommand = `echo "${sanitizeInput(maliciousInput)}"`;
// Verify output is escaped, not executed
middleBrick's continuous monitoring can verify that remediated code maintains secure patterns over time, alerting if new vulnerabilities are introduced through code changes.