T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/main.py:183
- Finding
- Arbitrary Code Execution Through User-Controlled Pandas Query<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py`, lines 183-192 **Vulnerability Type**: Unsafe expression evaluation **Risk Level**: High ### Vulnerable Code ```python if condition: # Basic safety check if any(op in condition for op in ['import', 'exec', 'eval', '__']): print("Error: Invalid condition - contains unsafe operations") return df try: filtered = df.query(condition, engine='python') print(f"Filtered from {len(df)} to {len(filtered)} rows") return filtered except: print(f"Error parsing condition: {condition}") print("Try format: 'column > value' or 'column == \"string\"'") return df ``` ### Technical Analysis The `--where` command-line argument, or the condition entered in interactive mode, is passed to `DataFrame.query()` using the Python evaluation engine. This makes the filtering expression an executable expression rather than a strictly parsed comparison. The preceding substring blacklist is not an adequate security boundary. It only rejects expressions containing `import`, `exec`, `eval`, or `__`. It does not enforce a grammar or prevent access to other objects and callable attributes available through the pandas evaluation environment. A crafted expression can therefore invoke a reachable dangerous function without containing any blocked substring. Even if the resulting expression is not a valid boolean filter, its side effects may occur before pandas reports an error. ### Attack Path 1. An attacker controls a condition supplied through `filter --where` or convinces a user or automation agent to process an attacker-provided condition. 2. The attacker constructs a pandas expression that reaches a command-execution function through an object available to the query environment while avoiding the four blocked substrings. 3. The blacklist accepts the expression. 4. `df.query(condition, engine='python')` evaluates it in the local Python pro ...[truncated 825 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Do not pass untrusted filtering text to `DataFrame.query()`, particularly with `engine='python'`. - Implement a strict parser for the documented filtering language. - Permit only: - Exact column names from the loaded DataFrame - Explicitly supported comparison operators - Typed string, numeric, boolean, and null literals - A small allowlist of boolean operators, if required - Construct boolean pandas masks directly after parsing, such as `df[column] > numeric_value`. - Reject function calls, attribute access, indexing into arbitrary objects, `@` references, and all syntax outside the supported grammar. - Return a failure rather than the original unfiltered DataFrame when a condition is invalid. Returning the full dataset can cause unintended disclosure or export. - Add regression tests containing known expression-injection patterns and verify that no callable object can be reached. - If a third-party expression parser is used, configure an explicit AST-node allowlist and ensure that evaluation cannot access Python globals, locals, built-ins, or object attributes. ]]>
