T09 · Insecure Skill Coding Practices
- Location
scripts/database_connector.py:296- Finding
SQL Injection Through Unvalidated Database Identifiers and LIMIT Values
- Content
View full analysis
pd.DataFrame: """获取表结构""" if self.dialect in ("sqlite", "sqlite3"): sql = f"PRAGMA table_info({table})" elif "postgresql" in self.dialect: sql = f""" SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name = '{table}' ORDER BY ordinal_position """ elif "mysql" in self.dialect: sql = f"DESCRIBE `{table}`" else: sql = f""" SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '{table}' """ return self.execute(sql).df def table_preview(self, table: str, limit: int = 5) -> pd.DataFrame: """预览表数据""" sql = f"SELECT * FROM `{table}` LIMIT {limit}" return self.execute(sql).df ``` ### Technical Analysis The `table` argument is interpolated directly into several SQL statements without validation or dialect-aware identifier quoting. The PostgreSQL and generic branches place it inside a string literal, while the SQLite and MySQL branches place it in identifier contexts. The `limit` argument is also interpolated directly, despite its type annotation not enforcing its runtime type. An external caller can pass a string or another object whose string representation contains SQL syntax. Ordinary parameter binding generally cannot be used for table names, but that does not make direct interpolation safe. Identifiers must instead be checked against a strict allowlist or quoted through the active database dialect. Whether stacked statements are accepted depends on the selected database driver, but injection can still modify predicates, access uni ...[truncated 1661 chars]- Remediation
View remediation
