Command Injection in Hapi with Jwt Tokens
Command Injection in Hapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an API passes untrusted input directly to a system shell or process builder. In Hapi, this typically arises in routes that invoke external utilities (for example, image conversion, archive extraction, or report generation) and embed data from the request into shell commands. When JWT tokens are used for authentication, developers may inadvertently place token data into those commands—either by parsing the token on the server to extract a role or tenant identifier, or by forwarding claims from the token into dynamic parameters.
If the application builds a command string using values derived from the JWT (such as a username, scope, or custom claim) without strict validation and escaping, an attacker who can influence the token payload (forged token, compromised client, or confused deputy) can inject shell metacharacters. For example, a claim like sub or a custom role claim could contain ;, &, or backticks. When these values are interpolated into commands executed via child processes, the attacker can run arbitrary code on the host, bypassing intended access controls encoded in the token itself.
Because middleBrick scans the unauthenticated attack surface, it does not need valid JWTs to detect risky patterns. It examines runtime behavior and OpenAPI specifications to identify endpoints that accept user-controlled data and interact with the host process. If the spec or implementation shows that data derived from authentication (including JWT claims) influences process invocation, middleBrick flags this as a high-severity finding and maps it to relevant attack patterns such as OS Command Injection under OWASP API Top 10.
Jwt Tokens-Specific Remediation in Hapi — concrete code fixes
Remediation focuses on never passing data derived from JWT tokens directly to shell commands. Instead, use structured, language-level APIs for external processes and rigorously validate or sanitize any data that originates from the token.
Principle: Avoid shell interpolation entirely
Use built-in process APIs that accept arguments as arrays, bypassing the shell. This neutralifies metacharacters that enable injection.
const Hapi = require('@hapi/hapi');
const { execFile } = require('child_process');
const jwt = require('jsonwebtoken);
const server = Hapi.server({ port: 4000, host: 'localhost' });
server.route({
method: 'GET',
path: '/report',
options: {
auth: {
strategy: 'jwt',
scope: ['read:reports']
}
},
handler: (request, h) => {
// request.auth.credentials contains the decoded JWT payload
const claims = request.auth.credentials;
// Validate and constrain values from JWT before use
const allowedFormats = ['pdf', 'csv'];
const format = request.query.format;
if (!allowedFormats.includes(format)) {
return h.response('Invalid format').code(400);
}
// Use execFile with explicit arguments; do not build a shell string
return new Promise((resolve, reject) => {
execFile(
'convert',
['--input-format', 'json', '--output-format', format, '/tmp/data.json'],
(error, stdout, stderr) => {
if (error) {
return reject(new Error('Report generation failed'));
}
resolve(stdout);
}
);
});
}
});
server.start();Principle: Strict validation and allowlists
If you must derive values from JWT claims, constrain them tightly. Use allowlists for identifiers such as usernames or tenant IDs. Do not rely on blacklists or simple pattern matching.
// Example: validating a tenant identifier from a JWT claim before any use
function getTenantDirectory(tokenPayload) {
const tenantId = tokenPayload.tenant_id;
// Allow only alphanumeric and underscores, length limits
if (!/^[a-zA-Z0-9_]{1,32}$/.test(tenantId)) {
throw new Error('Invalid tenant identifier');
}
return `/data/${tenantId}`;
}
// Safe usage: no shell involved
server.route({
method: 'GET',
path: '/files',
options: {
auth: 'jwt',
handler: (request, h) => {
const dir = getTenantDirectory(request.auth.credentials);
// Use platform APIs that do not invoke a shell
return fs.promises.readdir(dir);
}
}
});Principle: Secure token handling and verification
Ensure JWT verification is strict (use strong algorithms, validate issuer and audience) so that attackers cannot forge tokens to introduce malicious claims. Even with safe process invocation, a compromised token can lead to privilege escalation if the server trusts claims for access decisions.
jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://auth.example.com',
audience: 'api.example.com'
}, (err, decoded) => {
if (err) { throw err; }
// decoded is trusted and validated
});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 |