T09 · Insecure Skill Coding Practices
Note
- Location
- analyzer_parser.py:128
- Finding
- Malformed EXPLAIN JSON Causes Unhandled Exceptions<![CDATA[ ## Vulnerability Details **File Location**: `analyzer_parser.py:128-136`, `analyzer_parser.py:142-154`, and `analyzer_parser.py:182-191` **Vulnerability Type**: Improper input type and schema validation resulting in denial of service **Risk Level**: Low ### Vulnerable Code ```python try: data = json.loads(explain_json) except json.JSONDecodeError: result["error"] = "Invalid JSON format" return result qb = data.get("query_block", data) cost_info = qb.get("cost_info", {}) query_cost = cost_info.get("query_cost") result["query_cost"] = query_cost ``` ```python table_info = qb.get("table", {}) if isinstance(table_info, dict): access_type = table_info.get("access_type", "UNKNOWN") result["access_type"] = access_type result["key_used"] = table_info.get("key") rows_examined = table_info.get("rows_examined_scan") or table_info.get("rows_examined", 0) rows_produced = table_info.get("rows_produced", 0) result["rows_examined"] = rows_examined result["rows_produced"] = rows_produced table_name = table_info.get("table_name", "unknown") warnings, suggestions = _analyze_access_type( access_type, table_name, table_info, query_cost ) ``` ```python def _analyze_access_type( access_type: str, table_name: str, table_info: Dict, query_cost: Optional[str] ) -> tuple: """Generate warnings and suggestions based on the access type.""" warnings = [] suggestions = [] type_lower = access_type.lower() ``` ### Technical Analysis The parser verifies only that the input is syntactically valid JSON. It does not verify that the decoded value is an object or that nested properties have the expected types. For example: - `[]` or `null` is valid JSON but has no `.get()` method. - `{"query_block":[]}` causes `.get()` to be called on a list. - `{"query_block":{"cost_info":[]}}` causes `.get()` to be called on a list. - `{"query_block":{"table":{"access_type":1}}}` passes the table dictionar ...[truncated 1523 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require the decoded top-level value to be a dictionary: ```python try: data = json.loads(explain_json) except (json.JSONDecodeError, TypeError): result["error"] = "Invalid JSON format" return result if not isinstance(data, dict): result["error"] = "EXPLAIN JSON must be an object" return result ``` 2. Validate every nested object before calling `.get()`: ```python qb = data.get("query_block", data) if not isinstance(qb, dict): result["error"] = "query_block must be an object" return result cost_info = qb.get("cost_info", {}) if not isinstance(cost_info, dict): result["error"] = "cost_info must be an object" return result ``` 3. Normalize and validate scalar values: ```python access_type = table_info.get("access_type", "UNKNOWN") if not isinstance(access_type, str): access_type = "UNKNOWN" result["warnings"].append("Invalid access_type value") ``` 4. Validate row counters as non-negative integers before arithmetic or conversion. Reject booleans, which Python otherwise treats as integers. 5. Add a defensive exception boundary at the CLI or API entry point so malformed user input returns a controlled error rather than a traceback. 6. Add regression tests for: - `null` - Arrays and scalar top-level JSON values - Non-object `query_block`, `cost_info`, and `table` values - Numeric or null `access_type` - String, null, negative, and excessively large row counters ]]>
