T09 · Insecure Skill Coding Practices
- Location
sql_query_generator.py:498- Finding
Unvalidated SQL Fragments Permit SQL Injection
- Content
View full analysis
Vulnerability Details
File Location:
sql_query_generator.py:498-511
Vulnerability Type: SQL injection through unvalidated query fragments
Risk Level: HighVulnerable Code:
python query += f"{join_type} JOIN\n {join_table} ON {join['on']}\n" if where_conditions: query += "WHERE\n " + "\n AND ".join(where_conditions) + "\n" if group_by: validated_group_by = [ self.validator.validate_identifier(col, security_level=self.security_level) for col in group_by ] query += "GROUP BY\n " + ",\n ".join(validated_group_by) + "\n" if having: query += f"HAVING\n {having}\n"Technical Analysis
Although table names, column names, and ordering directions receive allowlist validation, the following caller-supplied SQL fragments are inserted directly into the generated query:
join['on']- Elements of
where_conditions having
These inputs are neither parsed into structured expressions nor checked against a strict grammar. They are also not converted into placeholders with separately returned parameter values. Consequently, an attacker who can influence any of these arguments can append arbitrary SQL syntax.
The documented claim that parameterization is mandatory does not mitigate this issue because the generator accepts complete predicate strings rather than enforcing parameterized predicate construction.
Attack Path
- An application accepts reporting, filtering, or join criteria from an untrusted user.
- The application passes attacker-controlled content to
where_conditions,joins[*]['on'], orhaving. - The attacker supplies a fragment such as
1 = 1; DROP TABLE users--, subject to the capabilities of the database driver. generate_select_query()concatenates the fragment into the SQL output without validation.- The application executes the generated query using a database connection.
- The inject ...[truncated 760 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace raw SQL fragment arguments with a structured expression model containing separately validated fields:
- Column identifier
- Operator selected from a fixed allowlist
- Bound value
- Boolean connector selected from
ANDorOR
- Return parameter values separately from generated SQL and require database-driver binding.
- Validate every JOIN operand as an identifier and permit only explicitly supported comparison operators.
- Build HAVING expressions from validated aggregate functions, identifiers, operators, and placeholders.
- Reject semicolons, SQL comments, stacked statements, and malformed expressions as defense in depth. Pattern rejection must not replace structural parsing and parameterization.
- Consider using database-driver identifier composition APIs or a mature SQL abstract syntax tree/query-builder library.
- Add tests proving that attacker-controlled JOIN, WHERE, and HAVING fragments cannot introduce additional clauses or statements.
- Replace raw SQL fragment arguments with a structured expression model containing separately validated fields:
