T09 · Insecure Skill Coding Practices
Error
- Location
- skill.json:14
- Finding
- Shell Command Injection Through Unescaped Tool Command Templates## Vulnerability Details **File Location**: `skill.json`, lines 14, 51, 78, and 83 **Vulnerability Type**: Shell command injection through unescaped template interpolation **Risk Level**: High **Classification**: T09: Insecure Skill Coding Practices ### Vulnerable Code ```json "command": "node {{workspace}}/brave_search.js --query \"{{query}}\" --count {{count|10}} --country {{country|us}} --freshness {{freshness|}} --extra-snippets {{extra_snippets|false}} --summary {{summary|false}}", ``` ```json "command": "node {{workspace}}/brave_suggest.js --query \"{{query}}\" --count {{count|5}} --country {{country|US}} --rich {{rich|false}}", ``` ```json "command": "node {{workspace}}/brave_spellcheck.js --query \"{{query}}\" --country {{country|US}}" ``` ```json "command": "node {{workspace}}/brave_answers.js --query \"{{query}}\" --country {{country|us}} --enable-citations {{enable_citations|true}} --enable-research {{enable_research|false}} --enable-entities {{enable_entities|false}} --stream {{stream|true}}", ``` ### Technical Analysis All four tool definitions construct commands by directly interpolating user-controlled values into a command string. The `query` parameter is placed between double quotes, but this does not provide safe shell escaping. An embedded double quote can terminate the intended argument, after which shell operators may introduce an additional command. Other interpolated fields, such as `country`, are also inserted as shell text rather than passed as structured process arguments. Exploitability depends on the Skill runtime invoking the generated command through a shell or equivalent command-string parser. Under that common execution model, a malicious query can alter command structure instead of remaining a single argument. For example, a query shaped like the following could terminate the quoted argument and append another command: ```text "; touch /tmp/skill-injection; # ``` This ...[truncated 1534 chars]
- Remediation
- ## Remediation Suggestions 1. Replace command strings with a structured executable-and-arguments format so the runtime launches Node.js without invoking a shell. For example: ```json { "executable": "node", "arguments": [ "{{workspace}}/brave_search.js", "--query", "{{query}}", "--count", "{{count|10}}", "--country", "{{country|us}}" ] } ``` 2. Configure the runtime to use an API equivalent to `spawn` or `execFile` with `shell: false`, passing each value as a separate argument. 3. Apply the same correction to all four affected tool definitions. Protect every interpolated field, not only `query`. 4. Enforce schema validation before execution: - Restrict `country` to a valid two-letter country code. - Restrict numeric values to documented ranges. - Restrict booleans and enumerated options to expected values. - Preserve queries as opaque string arguments rather than shell fragments. 5. If the platform only supports command strings, use the platform’s documented, context-appropriate shell-escaping facility for every substituted value. Do not rely on surrounding values with double quotes or on custom ad hoc escaping. 6. Add regression tests containing quotes, command substitutions, semicolons, pipes, redirection operators, and newline characters. Verify that these inputs are delivered literally to the JavaScript process and never interpreted as shell syntax. 7. Run the Skill with a restricted environment and filesystem permissions to reduce impact if another command-construction flaw is introduced.
