T09 · Insecure Skill Coding Practices
- Location
scripts/save_url_params.py:35- Finding
SQL Injection Through Attacker-Controlled URL Parameter Names
- Content
View full analysis
Vulnerability Details
File Location:
scripts/save_url_params.py:35-41andscripts/save_url_params.py:62-67
Vulnerability Type: SQL injection through unvalidated identifiers
Risk Level: HighVulnerable Code:
python # Build column definitions column_defs = ", ".join(f"{col} VARCHAR(255)" for col in columns) create_sql = f""" CREATE TABLE IF NOT EXISTS {TABLE_NAME} ( id INT AUTO_INCREMENT PRIMARY KEY, {column_defs} ) """ cursor.execute(create_sql)python columns = ", ".join(flat_params.keys()) placeholders = ", ".join(["%s"] * len(flat_params)) values = list(flat_params.values()) insert_sql = f"INSERT INTO {TABLE_NAME} ({columns}) VALUES ({placeholders})" cursor.execute(insert_sql, values)Technical Analysis
URL query parameter names originate from user-controlled input and are used directly as SQL column identifiers. Although the inserted values use parameter placeholders, placeholders do not protect table or column identifiers. Consequently, a specially crafted parameter name can introduce SQL syntax into both the
CREATE TABLEstatement and the subsequentINSERTstatement.The exact ability to execute multiple statements depends on the MySQL connector configuration and server behavior. Even where stacked statements are disabled, malicious identifiers can still alter query structure, trigger persistent schema problems, or repeatedly cause database errors and denial of service.
Attack Path
- An attacker supplies a URL containing a specially crafted query parameter name.
parse_qs(parsed.query)preserves that attacker-controlled name as a dictionary key.flat_params.keys()is passed tocreate_table_if_not_exists().- The name is interpolated without validation into
column_defs. - The same name is later interpolated into the
INSERTcolumn list. - MySQL parses and executes SQL whose structure is partially controlled by th ...[truncated 750 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not derive database columns directly from URL parameter names. Prefer a fixed normalized schema such as
url_id,parameter_name, andparameter_value. - If dynamic identifiers are unavoidable, enforce a strict allowlist such as
^[A-Za-z_][A-Za-z0-9_]{0,63}$. - Reject reserved words, duplicate normalized names, oversized identifiers, and all names that fail validation.
- Quote identifiers using a connector-supported, database-specific mechanism after validation. Do not treat quoting alone as sufficient validation.
- Continue using bound parameters for values.
- Execute database operations through a dedicated account with access only to the required schema and operations.
- Add tests using punctuation, spaces, backticks, parentheses, comments, reserved words, and oversized query keys to verify rejection.
- Do not derive database columns directly from URL parameter names. Prefer a fixed normalized schema such as
