Back to skill

Security audit

CSV Data Processor

Security checks for vulnerabilities and agentic risk

Overview

This is a normal CSV toolkit, but its filter and SQL export features have unsafe implementations that deserve review before installation.

Install only if you will use it on trusted data and trusted filter expressions. Avoid letting web pages, documents, or untrusted users choose the --where expression, and review generated SQL before importing it into any database.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/csv_filter.py:29
Finding

Arbitrary Python Code Execution Through Unsafe Filter Evaluation

Content
View full analysis

Vulnerability Details

File Location: scripts/csv_filter.py, lines 29-47
Vulnerability Type: Unsafe evaluation of user-controlled expressions
Risk Level: High

Vulnerable Code

python
if args.where:
    filtered = []
    for row in data:
        env = {k: v for k, v in row.items()}
        # Try numeric conversion for comparison
        for k, v in env.items():
            try:
                env[k] = int(v)
            except ValueError:
                try:
                    env[k] = float(v)
                except ValueError:
                    pass
        try:
            if eval(args.where, {"__builtins__": {}}, env):
                filtered.append(row)
        except Exception as e:
            print(f"Filter error: {e}")
            sys.exit(1)
    data = filtered

Technical Analysis

The value supplied through the --where command-line argument is passed directly to Python's eval(). Although the global namespace replaces __builtins__ with an empty dictionary, this does not create a secure sandbox.

Python expressions can traverse the object model through attributes such as class metadata, base classes, subclasses, and function global namespaces. Depending on classes already loaded in the interpreter, an attacker may recover access to built-in functions or other runtime capabilities. This can permit file access, module loading, or operating-system command execution.

The documented interface encourages users or an AI Agent to place filter expressions directly in --where. Therefore, an attacker who influences that expression can cross the boundary from data filtering into arbitrary Python execution.

Attack Path

  1. An attacker supplies or recommends a crafted value for the --where argument.
  2. A user or AI Agent invokes csv_filter.py with that expression.
  3. The script passes the expression to eval() for every CSV row.
  4. The express ...[truncated 926 chars]
Remediation
View remediation

Remediation Suggestions

Remove eval() entirely and implement an allowlisted expression parser.

  1. Parse the expression with ast.parse() in expression mode or use a dedicated filtering grammar.
  2. Permit only the required syntax, such as:
    • Boolean operations: and, or, and not
    • Comparisons: equality, inequality, and ordered comparisons
    • Column identifiers
    • String and numeric literals
  3. Explicitly reject function calls, attribute access, subscripting, comprehensions, lambda expressions, imports, and all other AST node types.
  4. Validate every identifier against the CSV column names.
  5. Evaluate the validated syntax through custom comparison logic rather than compiling and executing it as Python.
  6. Add tests containing object-traversal and function-call payloads to ensure they are rejected.
  7. If a full expression language is unnecessary, replace --where with structured arguments such as --column, --operator, and --value.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/csv_convert.py:36
Finding

SQL Injection Through Unquoted Identifiers and Unsafe Value Serialization

Content
View full analysis

Vulnerability Details

File Location: scripts/csv_convert.py, lines 36-62
Vulnerability Type: Injection into generated SQL statements
Risk Level: Medium

Vulnerable Code

python
def csv_to_sql(csv_path, delimiter, encoding, has_header, table):
    with open(csv_path, 'r', encoding=encoding) as f:
        reader = csv.reader(f, delimiter=delimiter)
        rows = list(reader)
    if not rows:
        return ""
    if has_header:
        cols = rows[0]
        data = rows[1:]
    else:
        cols = [f"col{i}" for i in range(len(rows[0]))]
        data = rows

    lines = [f"-- Converted from {csv_path}", f"CREATE TABLE IF NOT EXISTS {table} ({', '.join(cols)});", ""]
    for row in data:
        vals = []
        for v in row:
            if v == '' or v is None:
                vals.append('NULL')
            else:
                try:
                    float(v)
                    vals.append(v)
                except ValueError:
                    vals.append(repr(v))
        lines.append(f"INSERT INTO {table} ({', '.join(cols)}) VALUES ({', '.join(vals)});")
    return '\n'.join(lines)

Technical Analysis

The SQL converter builds statements through direct string interpolation. Three attacker-influenced inputs are embedded without SQL-aware validation or escaping:

  • The table value originates from the --table command-line argument.
  • Column identifiers originate from the first row of the CSV file.
  • Data values are serialized with Python's repr(), which is not an SQL literal encoder.

SQL identifiers have dialect-specific quoting requirements. Directly joining CSV headers into CREATE TABLE and INSERT statements allows delimiters, parentheses, comments, and statement terminators in a malicious header to alter the generated SQL structure. The --table argument presents the same problem.

Python repr() also does not guarantee valid or sa ...[truncated 1762 chars]

Remediation
View remediation

Remediation Suggestions

Replace ad hoc SQL construction with dialect-aware generation.

  1. Define the supported target SQL dialect explicitly.
  2. Validate table and column names against a conservative identifier policy, such as letters, digits, and underscores with a valid leading character.
  3. Alternatively, quote identifiers using the exact rules of the selected database dialect, including escaping embedded quote characters.
  4. Do not use Python repr() to serialize SQL values.
  5. Prefer importing through a database API using parameterized statements rather than generating executable SQL text.
  6. If SQL text must be generated, use a trusted dialect-aware library to encode literals.
  7. Avoid treating a value as safely numeric solely because float() accepts it; parse it into a numeric type and serialize the normalized value.
  8. Reject duplicate, empty, malformed, or excessively long column names.
  9. Add tests with quotes, statement terminators, comments, parentheses, Unicode characters, backslashes, and control characters in table names, headers, and values.
  10. Warn users that generated SQL must not be executed until its source data and identifiers are trusted.
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

eval() call detected

High
Category
Dangerous Code Execution
Confidence
93% confidence
Finding

The script evaluates a user-supplied --where expression with Python eval, which is inherently dangerous for untrusted input. Although __builtins__ is removed and only row values are exposed, eval still parses and executes arbitrary Python expressions and has a long history of sandbox bypasses and denial-of-service abuse; this makes the filter mechanism unsafe in a general-purpose agent skill context where inputs may be attacker-controlled.

Content

Scanner excerpt · scripts/csv_filter.py (reported line 43)May include surrounding context.

python
except ValueError:
                        pass
            try:
                if eval(args.where, {"__builtins__": {}}, env):
                    filtered.append(row)
            except Exception as e:
                print(f"Filter error: {e}")

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This markdown file documents commands that create output files such as combined.csv, joined.csv, and clean.csv, but it does not include any user-facing warning about potential overwrites or changes to user data. For markdown files, SQP-2 applies when the skill description omits warnings about behaviors that could affect user data or system integrity.

Content

No source excerpt is available for this finding.