T09 · Insecure Skill Coding Practices
- Location
private-secrets.sh:24- Finding
Arbitrary JavaScript and OS Command Execution Through Unescaped Secret Inputs
- Content
View full analysis
Vulnerability Details
File Location:
private-secrets.sh, lines 24-30 and 50-61
Vulnerability Type: JavaScript injection leading to arbitrary command execution
Risk Level: HighVulnerable code:
bash # Use node to update JSON node -e " const fs = require('fs'); const data = JSON.parse(fs.readFileSync('$SECRETS_FILE', 'utf8')); data['$NAME'] = '$VALUE'; fs.writeFileSync('$SECRETS_FILE', JSON.stringify(data, null, 2)); console.log('已添加: $NAME'); "The
getoperation uses the same unsafe source-code construction:bash node -e " const fs = require('fs'); const data = JSON.parse(fs.readFileSync('$SECRETS_FILE', 'utf8')); if (data['$NAME']) { console.log(data['$NAME']); } else { console.log('未找到: $NAME'); process.exit(1); } "Technical Analysis
The script inserts the user-controlled
NAMEandVALUEarguments directly into JavaScript source passed tonode -e. These values are not encoded, escaped, validated, or passed as data parameters.An attacker can include JavaScript quote delimiters and statements in a value, terminate the intended string literal, and inject additional JavaScript. Because Node.js exposes APIs such as
require('child_process'), successful JavaScript injection can be escalated directly to operating-system command execution.Shell quoting around the
node -eargument does not prevent this vulnerability. The shell first substitutes the variables, and Node.js subsequently parses the resulting text as executable JavaScript source.Attack Path
- The attacker gains the ability to invoke the skill or influence a secret name or value supplied to its
addcommand. - The attacker supplies a value containing a closing quote, an injected JavaScript statement, and a JavaScript comment marker. A conceptual payload can invoke
require('child_process').execSync(...). - The shell expands
$VALUEinside ...[truncated 1369 chars]
- The attacker gains the ability to invoke the skill or influence a secret name or value supplied to its
- Remediation
View remediation
Remediation Suggestions
-
Never concatenate user input into source passed to
node -e. -
Move the JavaScript implementation into a standalone script and obtain the command, name, value, and file path through
process.argv. -
If an inline program must be retained, pass values after the program and read them from
process.argv, for example:bash node - "$SECRETS_FILE" "$NAME" "$VALUE" <<'NODE' const fs = require('fs'); const [file, name, value] = process.argv.slice(2); const data = JSON.parse(fs.readFileSync(file, 'utf8')); data[name] = value; fs.writeFileSync(file, JSON.stringify(data, null, 2)); NODE -
Validate secret names against an explicit policy, such as a conservative length limit and an allowlist of letters, digits, underscores, periods, and hyphens.
-
Treat secret values strictly as opaque data; do not attempt to sanitize them for insertion into executable source.
-
Add regression tests using quotes, backslashes, newlines, comment markers, and JavaScript syntax in both names and values.
-
Return generic errors without including untrusted data in an executable or otherwise interpreted context.
-
