Back to skill

Security audit

sqlserver-tidb-replay

Security checks for vulnerabilities and agentic risk

Overview

This database replay skill is coherent in purpose, but it gives users high-impact database execution workflows with weak safety controls and a published root-password example.

Install only after reviewing the scripts and removing the hardcoded password example. Use a dedicated least-privileged TiDB account, never root, and run replay only against an isolated disposable test database. Treat captured SQL, JSON, CSV, and HTML reports as sensitive production data; redact or restrict access before sharing. Require TLS for remote TiDB connections, inspect replay JSON before execution, and do not open reports generated from untrusted inputs.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:326
Finding
Plaintext Administrative Database Credential Embedded in Documentation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:326-327` **Vulnerability Type**: Hardcoded plaintext credential **Risk Level**: High ### Vulnerable Code ```bash --user root \ --password "Xszyh@315315" \ ``` ### Technical Analysis The documentation contains a realistic plaintext password associated with the TiDB `root` account. Even if intended only as an example, it cannot be established from the repository that the credential is fictitious, expired, or isolated. Publishing it exposes the secret to every person and system with access to the Skill package. The example also promotes passing passwords through command-line arguments. Command-line secrets may be retained in shell history, terminal logs, CI logs, audit records, or process listings. Use of the database `root` account violates least-privilege principles because SQL replay generally requires access only to a designated test schema and a controlled subset of SQL operations. ### Attack Path 1. An attacker obtains the Skill package or reads `SKILL.md`. 2. The attacker extracts the documented username and password. 3. The attacker identifies an accessible TiDB endpoint associated with the project or tests the credential against environments where it may have been reused. 4. If valid, the attacker authenticates as `root`. 5. The attacker reads, modifies, or destroys any database resources available to that account. ### Impact Assessment If the credential is valid or reused, exploitation may grant full administrative access to a TiDB deployment. Potential consequences include: - Disclosure of all accessible database contents. - Modification or deletion of schemas and records. - Creation of additional accounts or privilege grants. - Disruption of migration and replay environments. - Credential reuse attacks against other systems. The potential privilege scope is especially broad because the documented account is `root`. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Immediately determine whether the exposed password has ever been valid. 2. Revoke or rotate the credential in every environment where it may have been used. 3. Replace it with an unmistakable placeholder such as `${TIDB_PASSWORD}` or `<REDACTED_TEST_PASSWORD>`. 4. Remove the credential from Git history, package caches, release artifacts, and generated documentation where feasible. 5. Do not recommend the TiDB `root` account. Create a dedicated replay account restricted to: - A disposable test database. - Only the required tables and operations. - Approved source hosts. - A limited validity period. 6. Retrieve credentials from a protected secret manager or prompt for them interactively. 7. Avoid passing secrets through command-line arguments. If environment variables are supported, warn that they may still be exposed in process environments and CI diagnostics. 8. Add automated secret scanning to repository and release workflows. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/replay_tidb.py:65
Finding
Unrestricted Execution of User-Controlled Replay SQL<![CDATA[ ## Vulnerability Details **File Location**: `scripts/replay_tidb.py:65-93` **Vulnerability Type**: Unrestricted execution of untrusted and potentially destructive SQL **Risk Level**: High ### Vulnerable Code ```python def replay_sql(conn, sql: str, sql_type: str) -> tuple[int, Optional[str], Optional[int], int]: """ 执行单条SQL 返回: (replay_duration_us, error_msg, error_code, row_count) """ start = time.perf_counter() try: with conn.cursor() as cursor: cursor.execute(sql) if sql_type.lower() in ("select", "cte", "merge"): results = cursor.fetchall() row_count = len(results) else: row_count = cursor.rowcount row_count = row_count if row_count is not None else 0 except pymysql.err.OperationalError as e: return int((time.perf_counter() - start) * 1_000_000), str(e), e.args[0] if e.args else None, 0 except pymysql.err.IntegrityError as e: return int((time.perf_counter() - start) * 1_000_000), str(e), e.args[0] if e.args else None, 0 except pymysql.err.ProgrammingError as e: return int((time.perf_counter() - start) * 1_000_000), str(e), e.args[0] if e.args else None, 0 except pymysql.err.DataError as e: return int((time.perf_counter() - start) * 1_000_000), str(e), e.args[0] if e.args else None, 0 except Exception as e: return int((time.perf_counter() - start) * 1_000_000), str(e), -1, 0 else: return int((time.perf_counter() - start) * 1_000_000), None, None, row_count ``` The untrusted value originates from replay input: ```python conn_id = item["conn_id"] sql = item["sql"] sql_type = item["sql_type"] ``` ### Technical Analysis The replay script loads SQL text from a user-selected JSON file and passes it directly to `cursor.execute`. It does not enforce an allowlist, reject destructive DDL, verify that the declared `sql_type` matches the statement, detect m ...[truncated 1877 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat replay files as untrusted input and validate every record before establishing database connections. 2. Default to a read-only allowlist, such as single `SELECT` statements. 3. Require explicit flags for each write category, for example: - `--allow-insert` - `--allow-update` - `--allow-delete` - `--allow-ddl` 4. Reject `DROP`, `TRUNCATE`, account-management statements, privilege changes, and administrative commands by default. 5. Parse SQL using a dialect-aware parser rather than regular-expression-only checks. 6. Reject multiple statements and ensure the parsed statement type matches `sql_type`. 7. Add a dry-run mode that produces a signed or reviewable execution manifest. 8. Require interactive confirmation before write or DDL replay, with a separate non-interactive override for controlled automation. 9. Require a dedicated least-privileged account restricted to a disposable test schema. 10. Add target-environment protections, such as production-host denylists or an explicit `--allow-production-target` acknowledgement. 11. Consider transaction wrapping and rollback where semantically possible. 12. Apply query timeouts and resource limits to reduce denial-of-service risk. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/replay_tidb.py:48
Finding
TiDB Connection Does Not Require or Verify TLS<![CDATA[ ## Vulnerability Details **File Location**: `scripts/replay_tidb.py:48-63` **Vulnerability Type**: Sensitive database traffic transmitted without enforced transport security **Risk Level**: High ### Vulnerable Code ```python def create_connection(host: str, port: int, user: str, password: str, database: str): """创建 TiDB 连接""" return pymysql.connect( host=host, port=port, user=user, password=password, database=database, charset="utf8mb4", cursorclass=pymysql.cursors.DictCursor, autocommit=True, connect_timeout=10, read_timeout=30, write_timeout=30, ) ``` ### Technical Analysis Connecting to TiDB is necessary for the Skill's declared replay functionality. However, the connection configuration does not specify TLS, a trusted certificate authority, certificate verification, or server hostname verification. Consequently, secure transport is not enforced by the client. Depending on server and PyMySQL behavior, credentials and replay traffic may be exposed to interception or modification. Replay SQL can include production-derived literals, personal data, tokens, account identifiers, and other sensitive information. The implementation also provides no explicit development-only override or warning when connecting to a remote host without verified TLS. ### Attack Path 1. An operator configures a remote TiDB host and runs the replay tool. 2. An attacker gains a position on the network path or controls DNS/routing for the target host. 3. Because the client does not require and validate TLS, the attacker intercepts the connection or impersonates the TiDB server where protocol conditions permit. 4. The attacker captures authentication material and sensitive SQL traffic or alters traffic between the client and server. 5. Captured credentials may then be used to access the actual TiDB server. ### Impact Assessment Potential impact includes: - Disclosure of ...[truncated 405 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require TLS for all non-loopback TiDB connections. 2. Add command-line or configuration options for: - CA certificate path. - Client certificate and private key, where mutual TLS is used. - Expected server hostname. 3. Configure PyMySQL with a verified SSL context that checks the certificate chain and hostname. 4. Fail closed when certificate validation cannot be completed. 5. If plaintext connections are needed for isolated local development, require an explicit option such as `--insecure-disable-tls` and display a prominent warning. 6. Never silently downgrade from TLS to plaintext. 7. Document certificate provisioning and rotation procedures. 8. Combine transport security with a dedicated, least-privileged replay account and network access controls. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/analyze_results.py:426
Finding
Stored HTML Injection Through Unescaped SQL and Report Metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/analyze_results.py:426-588` **Vulnerability Type**: Stored HTML injection and potential script execution **Risk Level**: High ### Vulnerable Code The report metadata is interpolated without HTML encoding: ```python <p>源数据库:<strong>{source_db}</strong></p> <p>目标数据库:<strong>{target_db}</strong></p> <p>回放耗时:{summary.get('elapsed_seconds', 'N/A')} 秒</p> <p>回放任务:{summary.get('task_name', 'N/A')}</p> ``` Captured SQL and database errors are also inserted directly into HTML: ```python <div class="sql-block before">{rec['sql']}</div> ``` ```python <td><div class="sql-block">{item['sql'][:150]}...</div></td> <td>{item.get('error', 'N/A')[:80]}</td> ``` ```python <td><div class="sql-block">{item['sql'][:100]}...</div></td> <td>{item.get('sql_type', 'N/A')}</td> ``` ### Technical Analysis The HTML report generator constructs markup through string interpolation without applying context-appropriate escaping. Several values are attacker-controllable or derived from untrusted data: - SQL text from replay result JSON. - Database error messages. - SQL type fields. - Task names and summary metadata. - `source_db` and `target_db` command-line arguments. An attacker can place HTML elements or JavaScript event handlers in SQL comments, quoted identifiers, metadata, or a crafted result file. When the report is generated, these values become executable markup rather than inert text. Truncating values does not neutralize markup. The generated document also has no restrictive Content Security Policy to mitigate injected active content. ### Attack Path 1. An attacker introduces an HTML payload into captured SQL, a replay JSON result, a database error message, or report metadata. 2. An operator runs `analyze_results.py`. 3. The payload is interpolated into the generated HTML without escaping. 4. A victim opens the report in a browser. 5. The browser interprets the payload as markup and may execute attacker-cont ...[truncated 648 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply `html.escape(value, quote=True)` to every untrusted value before inserting it into HTML. 2. Escape SQL, error messages, task names, database names, categories, descriptions, and summary fields independently. 3. Do not rely on truncation as a security control. 4. Validate values inserted into HTML attribute contexts, especially CSS class names, against strict allowlists. 5. Prefer a template engine with automatic HTML escaping enabled. 6. Add a restrictive Content Security Policy, for example disallowing scripts and remote resources where the report requires no JavaScript. 7. Add automated tests using payloads such as HTML tags, event handlers, quotes, and encoded markup. 8. Treat replay result files as untrusted, even when they are generated by another script in the same project. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/csv_to_sql.py:181
Finding
Sensitive SQL Text Is Unnecessarily Duplicated in Intermediate CSV Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/csv_to_sql.py:181-194` **Vulnerability Type**: Excessive retention of sensitive query content **Risk Level**: Medium ### Vulnerable Code ```python return { 'sql_text': sql, 'sql_type': detect_sql_type(sql), 'duration_ms': round(duration_ms, 2), 'database_name': db_name.strip(), 'session_id': str(session_id).strip(), 'start_time': start_time.strip(), 'syntax_flags': ','.join(syntax_flags) if syntax_flags else '', 'original_raw': raw_sql[:500], # 保存原始片段用于对比 } ``` The duplicated field is included in every output file: ```python fieldnames = [ 'sql_text', 'sql_type', 'duration_ms', 'database_name', 'session_id', 'start_time', 'syntax_flags', 'original_raw' ] ``` ### Technical Analysis The converter writes both normalized SQL and the first 500 characters of the original raw query into the output CSV. SQL logs frequently contain literals representing personal information, authentication tokens, financial identifiers, customer records, or other confidential application data. The `original_raw` field is not required by the replay pipeline. Retaining it by default increases the number of files and columns containing sensitive production-derived data. The output file is created with ordinary process-default permissions, with no explicit restriction, redaction, encryption, or retention control. Truncating the query to 500 characters does not reliably remove sensitive values and may preserve the most revealing portion of a statement. ### Attack Path 1. Production-derived SQL Server logs are passed to `csv_to_sql.py`. 2. Sensitive literals in each query are copied into both `sql_text` and `original_raw`. 3. The generated CSV is stored, transferred, backed up, or attached to a migration ticket. 4. An unauthorized user obtains access to the intermediate CSV. 5. The user extracts sensitive query values from `original_raw`, even where downst ...[truncated 654 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `original_raw` from default output because it is not required for replay. 2. If diagnostic retention is necessary, require an explicit opt-in option such as `--include-original-raw`. 3. Redact or tokenize string literals, numeric identifiers, comments, credentials, and known sensitive fields before writing diagnostics. 4. Store diagnostic output separately from replay input. 5. Create output files with restrictive owner-only permissions. 6. Document retention limits and securely delete intermediate files after analysis. 7. Avoid placing replay artifacts in shared directories, source control, or unrestricted object storage. 8. Consider encryption at rest for artifacts containing production-derived SQL. 9. Add warnings explaining that SQL logs may contain regulated or confidential data. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (9)

Missing User Warnings

High
Confidence
98% confidence
Finding
This script loads SQL statements from a JSON file and replays them directly against a live TiDB database with no validation, dry-run mode, confirmation prompt, or restriction to read-only statements. Because the input can contain destructive or dangerous statements such as DROP, DELETE, TRUNCATE, DDL changes, or TiDB-specific administrative SQL, running the tool on untrusted or mistaken input can cause data loss, schema corruption, or service disruption.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill describes collecting slow-query logs and transforming them into CSV/JSON artifacts containing raw SQL text, database names, session IDs, timestamps, and performance metadata without a clear privacy or data-handling warning. Such artifacts can contain sensitive business data, embedded literals, schema details, or operational metadata, and the absence of guidance increases the risk of accidental disclosure, insecure storage, or unsafe sharing of replay inputs and reports.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The documentation explicitly demonstrates replaying captured SQL that includes `insert`, `update`, and `delete` statements against TiDB, but it does not prominently warn that replay will execute writes and can alter or corrupt target data. In the provided migration/validation context, users may copy the example workflow and accidentally run production-derived write traffic against a non-isolated or insufficiently protected environment, causing integrity loss and unintended state changes.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This code file contains natural-language UI content that forces a specific locale: the HTML declares lang="zh-CN" and the surrounding report labels and messages are all in Chinese. Under the policy, language/locale constraints should not be imposed unless the skill offers a choice or clearly documents and justifies the restriction.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code file contains user-facing natural language exclusively in Chinese, including the top-level description and later CLI/help strings, which effectively imposes a specific language on users. The policy allows fixed locale behavior only when it is clearly justified as region-specific or when users are given a language/locale choice, neither of which is present here.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The argument help and option name imply that administrator/system SQL removal is a user-controllable behavior. However, parse_row unconditionally calls is_admin_sql and returns None for matching statements at L98-L99, and main never checks args.remove_admin before applying that filtering. This is an active contradiction between the documented interface and actual behavior.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file's natural-language strings, including the module docstring, error output, argument help text, and status messages, are written exclusively in Chinese. This imposes a fixed language/locale on users without any opt-in, which matches the language policy violation criteria.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The example invocation includes `--lang cn`, which indicates a fixed language/locale setting in the workflow. The document does not present this as optional or offer alternative locales, so it can be interpreted as enforcing a specific language without user opt-in.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This code file includes a natural-language locale policy choice with `--lang` defaulting to `cn`, which forces a specific language unless the user notices and overrides it. The policy allows language constraints only when the user is offered a choice or explicitly opts in; here a choice exists, but the default still imposes Chinese automatically.

Static analysis

No suspicious patterns detected.