T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:84
- Finding
- Arbitrary Python Code Execution Through Unsafe JWT Parameter Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 84–85 and 98–100 **Vulnerability Type**: User-controlled input embedded directly into Python source code **Risk Level**: High ### Vulnerable Code ```python token = '$TOKEN' secret = '$SECRET' ``` ```python import jwt # pip install PyJWT[crypto] try: decoded = jwt.decode('$TOKEN', '$PUBLIC_KEY', algorithms=['RS256'], audience='$EXPECTED_AUD') ``` These statements occur inside double-quoted `python3 -c` shell commands. The shell expands `$TOKEN`, `$SECRET`, `$PUBLIC_KEY`, and `$EXPECTED_AUD` before the resulting text is parsed as Python source. ### Technical Analysis The commands directly interpolate JWT-related values into single-quoted Python string literals. No escaping or safe argument-passing mechanism is used. If an attacker controls any interpolated value, a single quote can terminate the intended Python literal. The remaining value can then introduce arbitrary Python statements. For example, a malicious token value shaped like the following could escape the assignment and execute another statement: ```text '; __import__("os").system("attacker-controlled-command"); # ``` After shell expansion, the generated Python source would be equivalent to: ```python token = ''; __import__("os").system("attacker-controlled-command"); #' ``` Multiline public-key data also commonly contains line breaks. Embedding such data directly into a single-quoted Python literal can break parsing even when it is not malicious, while a deliberately crafted key can use the same condition for code injection. This is not merely a JWT validation failure. The input is inserted into the source code of the Python interpreter itself, creating an arbitrary local code-execution primitive. ### Attack Path 1. An attacker supplies or influences a token, secret, public key, or expected-audience value processed using the documented validation commands. 2. The supplied value includes a quote that closes the in ...[truncated 1337 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not place tokens, secrets, keys, audiences, or any other externally influenced values inside dynamically generated Python source. 1. Pass values through environment variables and retrieve them with `os.environ`: ```bash TOKEN="$TOKEN" SECRET="$SECRET" python3 -c ' import os import hmac import hashlib import base64 token = os.environ["TOKEN"] secret = os.environ["SECRET"] parts = token.split(".") if len(parts) != 3: raise SystemExit("Invalid JWT: expected three parts") signing_input = f"{parts[0]}.{parts[1]}".encode() signature = base64.urlsafe_b64decode(parts[2] + "==") expected = hmac.new(secret.encode(), signing_input, hashlib.sha256).digest() print("Signature VALID" if hmac.compare_digest(signature, expected) else "Signature INVALID") ' ``` 2. For public keys, use a key file or standard input rather than embedding multiline PEM data into source code: ```bash python3 verify_jwt.py --token "$TOKEN" --public-key-file "$PUBLIC_KEY_FILE" \ --audience "$EXPECTED_AUD" ``` 3. Prefer a dedicated, version-controlled Python script using `argparse` or another structured interface instead of complex inline `python3 -c` programs. 4. Validate the JWT structure before indexing token components, and reject malformed input with a controlled error. 5. Avoid exposing secrets in command-line arguments where they may be visible in process listings or shell history. Standard input, protected files, or a secret-management mechanism should be used for sensitive keys. 6. Add regression tests containing quotes, backslashes, newlines, malformed JWTs, and multiline PEM keys to confirm that all inputs are treated exclusively as data and can never alter executable code. ]]>
