T09 · Insecure Skill Coding Practices
- Location
SKILL.md:47- Finding
Removable Python Assertion Recommended as SQL Injection Defense
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 47–49
Vulnerability Type: Inadequate SQL identifier validation guidance
Risk Level: MediumVulnerable Code Snippet
markdown - **SQL/NoSQL injection** — table names, column names, or user input interpolated directly into query strings via f-strings or `%` formatting. Fix with allowlist validation (`assert table in frozenset({...})`); parameterised queries for values.Technical Analysis
The Skill recommends using a Python
assertstatement to enforce an allowlist for dynamic SQL identifiers. Assertions are intended for internal correctness checks, not security validation. Python removes them when the interpreter runs with optimization enabled, such as throughpython -OorPYTHONOPTIMIZE.If code generated according to this instruction constructs SQL using a user-controlled table name, optimized execution may eliminate the only identifier validation. Parameterized queries do not ordinarily support binding table or column names, so parameterization of values does not compensate for the missing identifier check.
The issue is in the Skill's hardening guidance rather than directly executable project code. Exploitation therefore depends on the Skill generating affected Python code, that code accepting an attacker-controlled SQL identifier, and deployment with assertions disabled.
Attack Path
- The Skill reviews Python code that dynamically inserts a table or column name into an SQL statement.
- Following
SKILL.md, it protects the identifier usingassert identifier in allowed_identifiers. - The resulting application is run with
python -O,python -OO, or an applicablePYTHONOPTIMIZEsetting. - Python removes the assertion from executed bytecode.
- An attacker supplies a crafted table or column identifier.
- The unchecked identifier is interpolated into the SQL statement.
- Subject to the database driver, query construction, and database account pri ...[truncated 609 chars]
- Remediation
View remediation
Remediation Suggestions
Replace assertion-based security checks with unconditional runtime validation and explicit failure handling:
python ALLOWED_TABLES = frozenset({"documents", "skills", "symlinks"}) if table not in ALLOWED_TABLES: raise ValueError("Unsupported table name")Apply equivalent validation to every dynamic SQL identifier, including table names, column names, sort directions, and schema names:
- Define allowlists using trusted constants rather than user-provided configuration.
- Perform explicit membership checks before constructing the query.
- Raise
ValueErroror a domain-specific exception when validation fails. - Continue using parameterized queries for all data values.
- Avoid permitting arbitrary identifier fragments, quoting syntax, expressions, or punctuation.
- Add tests that run under both standard and optimized Python modes to confirm that validation remains effective.
- Update the Skill text to state that
assertmust never enforce authentication, authorization, input validation, or other security boundaries.
