T09 · Insecure Skill Coding Practices
- Location
scripts/oil_price.sh:60- Finding
Remote API Response Injection Enables Arbitrary Python Code Execution in Real-Time Price Query
- Content
View full analysis
Vulnerability Details
File Location:
scripts/oil_price.sh:60-76
Vulnerability Type: Remote data injected into generated Python source
Risk Level: HighVulnerable Code
bash local url="https://map.360.cn/app/qcms?req=oil_price&cityid=${cityid}" # Use curl to retrieve data and process JSONP local response=$(curl -s "${url}" 2>/dev/null | sed 's/.*callback([^{]*)({).*/\1/g' | sed 's/}$//') if [ -z "$response" ] || [ "$response" == "null" ]; then echo "Unable to retrieve oil-price data" return 1 fi # Parse JSON and format output python3 << PYEOF import json import sys try: data = json.loads('''${response}''')Technical Analysis
The script obtains a response from the external
map.360.cnAPI and interpolates the response directly into an unquoted shell heredoc containing Python source code:python data = json.loads('''${response}''')Although the response is intended to be JSON, it is not passed to Python as data. It becomes part of the Python program before the interpreter parses that program. A response containing a closing triple quote, Python statements, and a suitable comment or trailing expression can escape the
json.loadsstring literal and introduce arbitrary Python code.For example, the structural form of a malicious response could terminate the string with
''', append Python statements, and comment out or otherwise neutralize the remaining source on that line. The injected statements would run when the heredoc is passed topython3, before JSON validation could provide any protection.HTTPS protects the connection against ordinary on-path modification when certificate validation succeeds, but it does not make the response safe to interpret as source code. The external API provider, a compromised API endpoint, or any actor capable of controlling a valid API response remains across a trust boundary.
Attack Path
- A user or agent invokes the documented entry point:
bash scrip
...[truncated 1188 chars]
- A user or agent invokes the documented entry point:
- Remediation
View remediation
Remediation Suggestions
Never interpolate network responses into Python source code. Pass the response through standard input or a securely created temporary file and parse it strictly as data.
A standard-input design can use:
bash if ! curl -fsS "$url" | python3 -c ' import json import sys data = json.load(sys.stdin) # Validate and format the expected fields here. '; then echo "Unable to retrieve or parse oil-price data" >&2 return 1 fiAlternatively:
- Create a temporary file with
mktemp. - Install a cleanup trap immediately.
- Write the response to that file without evaluating it.
- Pass only the file path as a Python argument.
- Parse it with
json.load. - Validate the top-level type, required fields, field types, and reasonable response size.
Example:
bash tmpfile=$(mktemp) || return 1 trap 'rm -f "$tmpfile"' RETURN curl -fsS --max-time 15 --max-filesize 1048576 "$url" > "$tmpfile" || return 1 python3 - "$tmpfile" <<'PYEOF' import json import sys with open(sys.argv[1], "r", encoding="utf-8") as handle: data = json.load(handle) if not isinstance(data, dict): raise ValueError("Unexpected response structure") PYEOFQuote the heredoc delimiter (
<<'PYEOF') whenever the heredoc contains fixed program source so that shell interpolation cannot modify that source.- Create a temporary file with
