T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/toolbox.py:657
- Finding
- Read-only SQL interface does not enforce read-only statements<![CDATA[ ## Vulnerability Details **File Location**: `scripts/toolbox.py:657-688` **Vulnerability Type**: Missing server-operation input validation **Risk Level**: High ### Vulnerable Code ```python def execute_sql( client: ToolboxClient, sql: str, instance_id: Optional[str] = None, database: Optional[str] = None, ) -> dict[str, Any]: try: if not sql: return _error("sql parameter cannot be empty") prep = _prepare(client, instance_id=instance_id, database=database) if not prep["ok"]: return prep["error"] p, ctx = prep["params"], prep["ctx"] if not p["database"]: return _error("database parameter is missing", {"missing": ["database"]}, context=ctx) req = { "instance_id": p["instance_id"], "instance_type": p["instance_type"], "database": p["database"], "commands": sql, "time_out_seconds": 60, } result = client.dbw.execute_sql(req) ``` The displayed error strings have been translated into English; the executable control flow is unchanged. ### Technical Analysis The function is documented and presented to the Agent as a read-only interface, but it does not inspect or classify the supplied SQL. Any non-empty string is copied directly into the `commands` field and sent to the remote `ExecuteSQL` operation. Instructions in `SKILL.md` tell the Agent not to use this function for DML or DDL, but prompt-level guidance is not a security boundary. Direct Python callers, command-line callers, compromised prompts, or later changes to Agent behavior can bypass those instructions. The implementation does not reject: - `INSERT`, `UPDATE`, or `DELETE` - `CREATE`, `ALTER`, or `DROP` - Administrative statements - Multiple statements separated by delimiters - Statements obscured by comments or dialect-specific syntax Whether a particular destructive statement completes also depends on database ...[truncated 1124 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse SQL with a dialect-aware parser before sending it to the API. 2. Require exactly one statement. 3. Allow only explicitly read-only statement types such as `SELECT`, `SHOW`, and `EXPLAIN`. 4. Reject DML, DDL, transaction-control, privilege-management, file-access, and administrative statements. 5. Reject stacked statements and ambiguous parse results. 6. Do not rely on keyword-prefix checks, because comments, common table expressions, and dialect-specific syntax can bypass them. 7. Enforce the same restrictions in the upstream DBW API as defense in depth. 8. Add tests covering mixed case, comments, stacked statements, writable common table expressions, and dialect-specific write operations. 9. Use separate credentials with database-level read-only permissions for this interface. ]]>
