T09 · Insecure Skill Coding Practices
- Location
scripts/execute_import.py:26- Finding
Unvalidated SQL Identifiers Allow SQL Injection During CSV Import
- Content
View full analysis
Vulnerability Details
File Location:
scripts/execute_import.py, lines 26-40 and 88-91
Vulnerability Type: SQL injection through dynamically interpolated identifiers
Risk Level: HighTechnical Analysis
The destination table and column names are inserted directly into SQL statements using f-strings. Parameterized placeholders are used only for row values; they do not protect the interpolated table name or destination column names.
SQLite implementation:
python cursor.execute( f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}'" ) if not cursor.fetchone(): raise ValueError(f"Table '{table_name}' does not exist") inserted = 0 for row in reader: values = [row.get(src, "") for src in mapping.keys()] try: cursor.execute( f"INSERT INTO {table_name} ({', '.join(dest_columns)}) VALUES ({placeholders})", values, )MySQL/MariaDB implementation:
python for row in reader: values = [row.get(src, "") for src in mapping.keys()] try: cursor.execute( f"INSERT INTO {table_name} ({', '.join(dest_columns)}) VALUES ({placeholders})", values, )table_namecomes from the--tablecommand-line argument, whiledest_columnscomes from the values of attacker-influenced--mappingJSON. Neither input is checked against the actual destination schema nor safely quoted as a database identifier.Although database drivers commonly reject multiple statements in a single
execute()call, that behavior does not make identifier interpolation safe. Crafted identifiers can alter the syntax and semantics of the existing statement without requiring a second statement. Exploitability and exact payloads depend on the selected database engine, schema, and connector settings.Attack Path
- An attacker supplies or influences the import command, mapping JSON, ...[truncated 1478 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not concatenate user-controlled identifiers into SQL.
- Retrieve the destination schema first and require exact membership of the requested table and destination columns.
- Reject empty identifiers, unknown identifiers, duplicates, control characters, comments, quotes, whitespace, and SQL metacharacters.
- Quote validated identifiers using database-specific rules:
- SQLite: double-quote identifiers and escape embedded double quotes.
- MySQL/MariaDB: use connector-supported identifier composition where available, or backtick only after strict schema validation and escaping.
- Keep parameterized placeholders for all row values.
- Verify that every source mapping key exists in the CSV and every destination mapping value exists in the selected table.
- Avoid recommending an administrative account. Use a dedicated importer account restricted to
INSERTand any narrowly required schema. - Add security tests using malicious table and column names, including quotes, comments, parentheses, commas, and SQL keywords.
