T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/setup.sh:49
- Finding
- Arbitrary Code Execution Through Python Source Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh`, lines 49-72 **Vulnerability Type**: Shell-to-Python command injection **Risk Level**: Critical ### Vulnerable Code ```bash ENV_JSON=$(python3 -c " import json env = {'KASPA_NETWORK': '$NETWORK'} if '$MNEMONIC': env['KASPA_MNEMONIC'] = '$MNEMONIC' if '$INDEXER_URL': env['KASIA_INDEXER_URL'] = '$INDEXER_URL' print(json.dumps(env)) ") # Add kasia to mcporter config python3 -c " import json with open('$MCPORTER_CONFIG') as f: config = json.load(f) config.setdefault('mcpServers', {}) config['mcpServers']['kasia'] = { 'command': 'node $KASIA_MCP_PATH/dist/index.js', 'env': $ENV_JSON } with open('$MCPORTER_CONFIG', 'w') as f: json.dump(config, f, indent=2) f.write('\n') print('Added kasia to', '$MCPORTER_CONFIG') " ``` ### Technical Analysis The script inserts shell variables directly into source code passed to `python3 -c`. The values of `NETWORK`, `MNEMONIC`, and `INDEXER_URL` originate from command-line arguments. `MCPORTER_CONFIG` can be supplied through the environment, while `KASIA_MCP_PATH` is derived from a caller-selected path. Shell quoting does not make these values safe inside Python string literals. An attacker can include a single quote and additional Python syntax in one of these inputs, terminate the intended string literal, and inject statements such as calls to `os.system`, `subprocess.run`, or arbitrary filesystem operations. The generated `ENV_JSON` is subsequently inserted as Python source into a second interpreter invocation, creating another code-generation boundary. Configuration and project paths containing Python metacharacters can similarly alter that invocation. ### Attack Path 1. An attacker supplies a crafted value through `--network`, `--mnemonic`, or `--indexer-url`, or controls `MCPORTER_CONFIG` or the selected project path. 2. The crafted value closes the surrounding Python string literal. 3. The value appends syntactically valid ...[truncated 806 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Never interpolate shell variables into executable Python source. - Pass all values as positional arguments or environment variables and read them through `sys.argv` or `os.environ`. - Serialize data exclusively inside Python rather than constructing Python object literals in the shell. - Pass the configuration path and project path as data rather than embedding them in `open(...)` or command strings. - Validate `NETWORK` against an explicit allowlist. - Validate the indexer URL using a strict URL parser and an allowed-scheme policy. - Add regression tests containing apostrophes, quotes, newlines, backslashes, and Python syntax in every externally controlled value. - Prefer a dedicated Python script over complex multiline `python3 -c` programs. For example: ```bash ENV_JSON="$( NETWORK="$NETWORK" \ MNEMONIC="$MNEMONIC" \ INDEXER_URL="$INDEXER_URL" \ python3 - <<'PY' import json import os env = {"KASPA_NETWORK": os.environ["NETWORK"]} if os.environ.get("MNEMONIC"): env["KASPA_MNEMONIC"] = os.environ["MNEMONIC"] if os.environ.get("INDEXER_URL"): env["KASIA_INDEXER_URL"] = os.environ["INDEXER_URL"] print(json.dumps(env)) PY )" ``` The configuration update should likewise receive paths and serialized JSON through protected arguments or environment variables and parse them strictly as data. ]]>
