Command Injection in Adonisjs with Cockroachdb
Command Injection in Adonisjs with Cockroachdb — how this specific combination creates or exposes the vulnerability
Command injection occurs when an application passes untrusted input directly to a system command. In AdonisJS, this risk arises when developers use Node.js child process helpers (e.g., exec, spawn, or child_process) with data that originates from HTTP requests and is stored in CockroachDB. CockroachDB itself is a distributed SQL database and does not execute shell commands, but if query results or user-supplied values are interpolated into operating system commands, the database becomes indirectly relevant: data pulled from CockroachDB may be treated as safe simply because it is stored in a database, leading to unsafe usage downstream.
For example, consider a reporting endpoint in AdonisJS that accepts a table_name parameter, queries CockroachDB for column metadata, and then constructs a shell command using that value:
const { exec } = require('child_process');
const query = 'SELECT column_name FROM information_schema.columns WHERE table_name = $1';
const result = await db.query(query, [tableName]);
const columns = result.rows.map(r => r.column_name).join(',');
exec(`echo Columns: ${columns}`, (err, stdout) => { /* ... */ });
Here, tableName comes from the request and is used in a SQL query (parameterized safely), but the echoed columns are interpolated into a shell command. An attacker who can influence tableName could attempt to inject additional shell commands if the application logic allows multiple statements or special characters to reach exec. Even though CockroachDB enforces SQL semantics and prevents direct command execution, the database can become a vector when its output is concatenated into shell commands without validation.
Another scenario involves scheduled tasks or migrations that invoke shell utilities based on data stored in CockroachDB. If an attacker can write malicious metadata into the database (e.g., via another vulnerability), subsequent automated operations might execute those values as commands. This highlights the importance of treating database content as untrusted when it flows into OS-level operations. The combination of AdonisJS’s flexibility with process spawning and CockroachDB’s role as a data store increases the attack surface only when untrusted data bridges the two layers via insecure coding patterns.
Cockroachdb-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on preventing untrusted data from reaching the shell. Avoid shell interpolation entirely; use parameterized APIs and structured data handling. Below are concrete AdonisJS examples with CockroachDB that demonstrate secure practices.
1. Avoid shell commands when working with database metadata
Instead of using exec to echo columns, handle data in-process:
const query = 'SELECT column_name FROM information_schema.columns WHERE table_name = $1';
const result = await db.query(query, [tableName]);
const columns = result.rows.map(r => r.column_name).join(',');
// Process columns in JavaScript without shell involvement
console.log('Columns:', columns);
2. Use environment variables or configuration for static commands
If a shell command is unavoidable (e.g., invoking a trusted binary), do not inject any user-influenced data. Load configuration from environment variables and validate against a strict allowlist:
const allowedCommands = new Set(['/usr/bin/report', '/usr/bin/export']);
const userCommand = process.env.REPORT_CMD;
if (!allowedCommands.has(userCommand)) {
throw new Error('Invalid command');
}
const { execFile } = require('child_process');
execFile(userCommand, ['--format', 'json'], (err, stdout) => { /* ... */ });
3. Validate and sanitize all inputs before database or shell interaction
Use schema validation to restrict tableName to known values, ensuring only expected table names reach CockroachDB and downstream logic:
const { schema } = require('@ioc:Adonis/Core/Validator');
const tableNameSchema = schema.string({}, [rules.allowed(['users', 'products', 'orders'])]);
const validated = await validator.validate({ schema: tableNameSchema, data: { tableName } });
// Use validated.tableName safely in queries, never in shell commands
4. Prefer built-in database tools over shell utilities
For operations like backups or data exports, use CockroachDB’s native tools programmatically via HTTP or client libraries rather than shelling out. For example, use the official client to run SQL queries instead of invoking cockroach sql via exec.
const { Client } = require('@cockroachdb/client');
const client = new Client({ connectionString: 'postgresql://user@localhost:26257/db' });
await client.connect();
const res = await client.query('SELECT * FROM my_table WHERE id = $1', [id]);
await client.end();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 |