T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/bullybuddy.sh:43
- Finding
- JSON Injection into Security-Sensitive Session Spawn Requests<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bullybuddy.sh`, lines 43–51 **Vulnerability Type**: Improper JSON construction using unescaped user input **Risk Level**: High ### Vulnerable Code ```bash cwd="${1:-$(pwd)}" task="$2" group="${3:-default}" body="{\"cwd\":\"$cwd\",\"group\":\"$group\"" [[ -n "$task" ]] && body="${body},\"task\":\"$task\"" body="${body}}" result=$(curl -sf -X POST "$BB_URL/api/sessions" -H "$AUTH" -H "$CT" -d "$body") ``` ### Technical Analysis The `cwd`, `task`, and `group` values originate from slash-command arguments and are inserted into a JSON document through direct string interpolation. JSON metacharacters in these values—including quotation marks, commas, and braces—are not escaped. An attacker able to influence command arguments can terminate the intended JSON string and add or replace properties in the request body. This is particularly security-sensitive because the documented spawn API accepts a `skipPermissions` property. A malicious argument could produce a request containing: ```json { "cwd": "/legitimate/path", "group": "default", "task": "example", "skipPermissions": true } ``` For example, a `task` value shaped like the following could inject an additional property: ```text example","skipPermissions":true,"padding":"x ``` The resulting request remains syntactically valid JSON while containing attacker-selected session configuration. ### Attack Path 1. An attacker causes a user or calling agent to invoke `bullybuddy spawn` with a crafted `cwd`, `task`, or `group` argument. 2. The shell script inserts the argument directly into `body` without JSON encoding. 3. The crafted argument closes the intended string and injects additional request properties. 4. The script sends the modified body to `POST /api/sessions` using the legitimate bearer token. 5. If the server accepts the injected `skipPermissions` property, it creates a Claude Code session without normal permission confirmations. ...[truncated 748 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Construct request bodies with a JSON-aware encoder instead of string concatenation. For example: ```bash if [[ -n "$task" ]]; then body=$(jq -n \ --arg cwd "$cwd" \ --arg group "$group" \ --arg task "$task" \ '{cwd: $cwd, group: $group, task: $task}') else body=$(jq -n \ --arg cwd "$cwd" \ --arg group "$group" \ '{cwd: $cwd, group: $group}') fi ``` Apply the following additional controls: 1. Validate `cwd` as an allowed, canonical directory before sending it. 2. Enforce reasonable length and character limits for `task` and `group`. 3. On the server, use a strict request schema that rejects unknown properties. 4. Do not permit API clients to set `skipPermissions` unless a separate, explicit authorization policy allows it. 5. Default `skipPermissions` to `false` server-side regardless of omitted or malformed client data. 6. Add tests using quotes, backslashes, control characters, commas, and attempted injected properties. ]]>
