Back to skill

Security audit

MySQL Slow Query Analyzer

Security checks for vulnerabilities and agentic risk

Overview

This is a local MySQL slow-query analysis skill with no evidence of hidden execution, network upload, persistence, or credential access.

Install only if Chinese-language MySQL performance guidance is acceptable. Treat index and rewrite recommendations as heuristics to review with a DBA before applying to production, and avoid exposing the parser directly as a long-running public service without input validation and exception handling.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

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 ]]>

T09 · Insecure Skill Coding Practices

Note
Location
mysql_slow_query_analyzer.py:116
Finding
Incomplete Slow-Query Logs Crash Text Report Formatting<![CDATA[ ## Vulnerability Details **File Location**: `mysql_slow_query_analyzer.py:116-119` **Vulnerability Type**: Unsafe formatting of nullable untrusted values resulting in denial of service **Risk Level**: Low ### Vulnerable Code ```python if data.get("log_info"): li = data["log_info"] if not li.get("error"): lines.append(f"⏱️ Query time: {li.get('query_time')}s ({li.get('severity', 'UNKNOWN')})") lines.append(f"🔒 Lock wait: {li.get('lock_time')}s") lines.append(f"📊 Rows examined: {li.get('rows_examined', 'N/A'):,}") lines.append(f"📨 Rows returned: {li.get('rows_sent', 'N/A'):,}") lines.append(f"📈 Scan efficiency: {li.get('efficiency_ratio', 'N/A')}") lines.append("") ``` ### Technical Analysis `parse_slow_query_log()` initializes `rows_examined` and `rows_sent` as explicit `None` values when the corresponding fields are missing. Dictionary `.get(key, default)` returns the stored `None`; the default is used only when the key is absent. Consequently, the following formatting expression attempts to apply the numeric comma-grouping format to `None`: ```python f"{li.get('rows_examined', 'N/A'):,}" ``` Python raises a `TypeError` because `NoneType` does not support this format specification. The same problem affects `rows_sent`. The parser permits an incomplete or malformed slow-query log to reach the formatter without setting an error, making the crash reachable through ordinary untrusted CLI input. ### Attack Path 1. An attacker supplies an incomplete slow-query log without `Rows_examined` or `Rows_sent`, for example: ```text # Query_time: 2.0 SELECT 1; ``` 2. `parse_slow_query_log()` returns a result in which the missing row counters are `None`. 3. The `slowlog` command passes that result to `_format_report()`. 4. `_format_report()` applies the `:,` numeric format to `None`. 5. Python raises an uncaught `TypeError`, terminating the CLI invocation. 6. Repeated submissions can cau ...[truncated 480 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Normalize nullable values before applying numeric formatting: ```python rows_examined = li.get("rows_examined") rows_sent = li.get("rows_sent") rows_examined_text = f"{rows_examined:,}" if isinstance(rows_examined, int) else "N/A" rows_sent_text = f"{rows_sent:,}" if isinstance(rows_sent, int) else "N/A" lines.append(f"📊 Rows examined: {rows_examined_text}") lines.append(f"📨 Rows returned: {rows_sent_text}") ``` 2. Consider marking a slow-query log as incomplete when required metadata is absent and return a controlled parser error or warning. 3. Apply explicit type checks rather than relying on `.get()` defaults where keys may exist with null values. 4. Catch expected formatting and input-validation failures at the CLI boundary and print a concise error without a traceback. 5. Add regression tests for logs containing: - SQL without metadata - `Query_time` without row counters - Only one of `Rows_examined` and `Rows_sent` - Empty or malformed numeric fields - Metadata with unusually large numeric values ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The skill description is written in Chinese and does not indicate any option for users to choose another language or locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger phrases include broad terms like "查询优化", "mysql explain", and "索引建议", which can activate the skill for general MySQL/database questions rather than only slow-query analysis. This can cause over-invocation, incorrect routing, and potentially unsafe or misleading optimization advice outside the intended scope, though it does not directly introduce code execution or data exfiltration risk.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This Python file contains natural-language documentation in mixed Chinese and English and later emits warnings/suggestions entirely in Chinese, indicating the skill is designed to communicate in a fixed language. The file does not offer user opt-in for language selection or document that the skill is region-specific, which fits the language/locale policy violation criteria.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
User-facing result strings such as warnings and remediation messages are emitted only in Chinese at these lines, and similar patterns recur throughout the file. Without a user-selectable locale or documented regional limitation, this constitutes a natural-language locale policy issue.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module docstring explicitly states its functions in Chinese, and the user-facing suggestion and recommendation strings throughout the file are also hard-coded in Chinese. For a general-purpose analyzer, this imposes a specific language/locale without opt-in or documented regional justification, which matches the language-policy violation criteria.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code file contains user-facing natural-language strings that present usage and reports in Chinese, and there is no option for the user to select another language or locale. Under the stated policy, forcing a specific language without opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This Python test file contains user-visible natural-language content in Chinese, including the module docstring and many test descriptions, but provides no indication that Chinese is optional or that the skill is intentionally locale-specific. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
This code presents its description, usage text, examples, and status messages in Chinese only. The file does not provide any language selection, fallback, or opt-in mechanism, which is a natural-language locale policy issue under the rule for forced language without user choice.

Static analysis

No suspicious patterns detected.