Command Injection in Feathersjs with Api Keys
Command Injection in Feathersjs with Api Keys — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an application passes untrusted input directly to a system shell or to a process constructor without proper sanitization. In FeathersJS, this risk can surface around API key handling when keys are used to trigger external workflows, logging, or integrations. If an API key value or a key-derived parameter is concatenated into a shell command—such as when invoking a script or a CLI tool to rotate keys, validate scopes, or call an external auth provider—user-controlled data may be executed as code.
Consider a FeathersJS service that accepts an API key and passes it to a shell command for validation via a custom hook. If the implementation uses string interpolation or concatenation without escaping, an attacker can supply a key like valid_key; id or valid_key && cat /etc/passwd. When the command executes, the additional shell instructions run with the same privileges as the application, enabling unauthorized commands, file reads, or environment manipulation. This pattern is especially risky when the service relies on external binaries that are not strictly sandboxed.
The LLM/AI Security checks in middleBrick test for scenarios where API key handling might lead to unsafe consumption or unsafe integrations, including cases where keys influence external tool invocation. Even though API keys are typically secrets, exposing them through logs or error messages can compound risk; if those logs are later used in automated workflows that construct commands, injection paths may emerge indirectly.
Real-world attack patterns mirror known issues in plugin ecosystems and custom hooks. For example, an improperly configured hook that runs a shell script to enforce key-specific rate limits could become a vector if input is not rigorously validated. OWASP API Top 10 A03:2023 (Injection) and A05:2023 (Broken Function Level Authorization) provide relevant context for how these weaknesses map to recognized classes of vulnerabilities.
Api Keys-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on avoiding shell command construction with untrusted data and validating or isolating API key usage. The safest approach is to bypass shell execution entirely, using native libraries or SDKs for any external operation. When you must invoke external processes, strict allowlists and parameterized execution are required.
Example 1: Unsafe usage to avoid
const { exec } = require('child_process');
app.service('hooks').before({
create(context) {
const apiKey = context.data.apiKey;
// Unsafe: directly concatenating user-controlled key into a shell command
exec(`node validate-key.js ${apiKey}`, (error, stdout, stderr) => {
if (error) throw error;
context.result = { stdout };
});
return context;
}
});
Example 2: Safe alternative using child_process with arguments array
const { spawn } = require('child_process');
app.service('hooks').before({
create(context) {
const apiKey = context.data.apiKey;
// Safe: using spawn with an array, no shell involved
const child = spawn('node', ['validate-key.js', apiKey]);
let stdout = '';
child.stdout.on('data', (data) => { stdout += data; });
child.on('close', (code) => {
if (code !== 0) throw new Error('Key validation failed');
context.result = { stdout };
});
// Ensure you handle errors and timeouts in production
return context;
}
});
Example 3: Validating API key format before use
app.service('hooks').before({
create(context) {
const apiKey = context.data.apiKey;
// Allowlist: only alphanumeric and underscores, 32–64 chars
if (!/^[A-Za-z0-9_]{32,64}$/.test(apiKey)) {
throw new Error('Invalid API key format');
}
// Proceed with non-shell integrations, e.g., internal validation or calling an SDK
context.result = { valid: true };
return context;
}
});
Example 4: Using an SDK instead of shell commands
const AuthProvider = require('some-auth-provider-sdk');
app.set('authProvider', new AuthProvider({})); // initialized with safe configuration
app.service('hooks').before({
create(context) {
const apiKey = context.data.apiKey;
// Use the provider’s native method to validate the key
const isValid = app.get('authProvider').validateKey(apiKey);
if (!isValid) throw new Error('Invalid API key');
context.result = { valid: true };
return context;
}
});
General hardening practices
- Never construct shell commands with concatenated user input; prefer native APIs or SDKs.
- If shell usage is unavoidable, use parameterized process invocation (e.g.,
spawnwith an argument array) and disable shell interpretation. - Apply strict allowlist validation on API key formats and enforce length and character constraints.
- Ensure secrets like API keys are not logged in full; mask or omit them from logs and error traces.
- Review hooks and services for indirect command construction via dependencies or plugins, as injection can occur transitively.
These practices align with secure coding guidance and help mitigate Injection while preserving the intended use of API keys for authentication and authorization.
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 |