T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/batch_send.sh:58
- Finding
- Arbitrary Python Code Execution Through Unsafely Interpolated Lead File Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/batch_send.sh`, lines 58-70 **Vulnerability Type**: Python source-code injection **Risk Level**: High ### Vulnerable Code ```bash # Count leads TOTAL=$(python3 -c "import json; print(len(json.load(open('$LEADS'))))") echo "📋 $TOTAL leads loaded from $LEADS" echo "⏱️ Delay: ${DELAY}s between messages" echo "📡 WAHA: $WAHA_URL (session: $SESSION)" [ "$DRY_RUN" = true ] && echo "🔍 DRY RUN MODE — no messages will be sent" echo "" SENT=0 FAILED=0 # Process each lead python3 -c " import json, sys leads = json.load(open('$LEADS')) ``` ### Technical Analysis The user-controlled `--leads` value is interpolated directly into source code passed to `python3 -c`. Shell quoting prevents the shell from immediately interpreting the value, but it does not escape the value for use inside a Python string literal. A filename containing a single quote and additional Python syntax can terminate the intended string and insert statements into either Python invocation. The earlier file-existence check does not prevent exploitation because Unix filenames may legally contain quote characters, semicolons, parentheses, and other characters useful for constructing valid Python syntax. This exceeds the privileges needed to read a JSON file. The path should be treated solely as data, but the implementation allows it to alter executable Python source. ### Attack Path 1. An attacker creates or distributes a JSON leads file whose filename contains Python syntax, or convinces the operator to invoke the script with an attacker-selected path. 2. The operator runs `batch_send.sh --leads <attacker-controlled-path> --waha-key <key>`. 3. The `-f` check succeeds because a file exists under the crafted name. 4. The shell expands `$LEADS` inside the double-quoted `python3 -c` argument. 5. Embedded quote characters terminate the Python string passed to `open()`, and the remaining filename content is parsed as Python statements. 6. ...[truncated 961 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Never construct Python source code using shell-controlled values. Pass the path as a positional argument: ```bash TOTAL=$(python3 -c \ 'import json, sys; print(len(json.load(open(sys.argv[1], encoding="utf-8"))))' \ "$LEADS") ``` Replace the second invocation similarly: ```bash python3 - "$LEADS" <<'PY' | import json import sys with open(sys.argv[1], encoding="utf-8") as file: leads = json.load(file) for lead in leads: name = lead.get("name", "Unknown") phone = ( lead.get("phone", "") .replace("+", "") .replace(" ", "") .replace("-", "") ) if phone: print(f"{phone}|{name}") PY while IFS='|' read -r PHONE NAME; do # Existing processing logic : done ``` Additional hardening should include: 1. Validate that the decoded JSON root is an array and that each entry is an object. 2. Validate phone numbers against a strict numeric format and reasonable length. 3. Reject files larger than an operationally necessary limit. 4. Avoid parsing structured records through a delimiter such as `|`, since lead names can contain that character; use a safer structured transport or null-delimited records. 5. Add regression tests using paths containing spaces, quotes, newlines, shell metacharacters, and Python syntax. 6. Run the script as an unprivileged account with access limited to the required lead files and WAHA endpoint. ]]>
