- Location
- scripts/catalog_builder.py:83
- Finding
- Command Injection in Generated Preview Curl Command<![CDATA[
## Vulnerability Details
**File Location**: `scripts/catalog_builder.py`, lines 83–93 and 136–143
**Vulnerability Type**: Shell command injection through unsafe command generation
**Risk Level**: High
**Category**: T09: Insecure Skill Coding Practices
### Vulnerable Code
The preview command embeds JSON containing user-controlled parameter values inside a single-quoted shell argument:
```python
def build_curl(tool, spider_parameters_json):
return " \\\n".join([
"curl -X POST '{}'".format(BUILDER_URL),
" -H 'Authorization: Bearer $DATAIFY_API_TOKEN'",
" -H 'Content-Type: application/x-www-form-urlencoded'",
" -d 'spider_name={}'".format(tool["spider_name"]),
" -d 'spider_id={}'".format(tool["tool_sign"]),
" -d 'spider_parameters={}'".format(spider_parameters_json),
" -d 'spider_errors=true'",
" -d 'file_name={{TasksID}}'",
])
```
The JSON is derived from command-line input or a user-supplied file and is printed as executable shell text:
```python
rows = map_select_labels(tool, load_rows(args.values_file, args.params_json))
validate_required(tool, rows)
```
```python
payload_json = json.dumps(rows, ensure_ascii=False, separators=(",", ":"))
if args.preview:
print(build_curl(tool, payload_json))
return 0
```
### Technical Analysis
JSON strings can legitimately contain apostrophes. Because `spider_parameters_json` is placed inside a shell single-quoted string without escaping, an apostrophe in a supplied parameter terminates the intended quoting context. Subsequent shell metacharacters can then be interpreted as commands.
The `--preview` path does not execute the command itself. However, it deliberately generates a curl command for users or agents to copy and execute, so untrusted data is converted into an executable command without safe encoding.
The authorization header also uses single quotes around `$DATAIFY_API_TOKEN`, which prevents ordinary POSIX shell
...[truncated 1258 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
1. Prefer structured preview output rather than executable shell text. For example, print the endpoint, headers with redacted credentials, and form fields as JSON.
2. If a shell command is required, apply `shlex.quote()` independently to every dynamic argument:
```python
import shlex
parts = [
"curl",
"-X", "POST",
BUILDER_URL,
"-H", "Authorization: Bearer $DATAIFY_API_TOKEN",
"-H", "Content-Type: application/x-www-form-urlencoded",
"-d", "spider_name={}".format(tool["spider_name"]),
"-d", "spider_id={}".format(tool["tool_sign"]),
"-d", "spider_parameters={}".format(spider_parameters_json),
"-d", "spider_errors=true",
"-d", "file_name={{TasksID}}",
]
preview = " ".join(shlex.quote(part) for part in parts)
```
3. Clearly label preview output as data rather than a trusted command when it contains user-supplied values.
4. Correct token expansion without exposing the token. If shell output remains supported, avoid quoting that accidentally turns `$DATAIFY_API_TOKEN` into a literal value while still preserving safe argument boundaries.
5. Add tests covering apostrophes, newlines, command substitutions, semicolons, and other shell metacharacters in catalog parameters.
]]>