Back to skill

Security audit

测试环境 MySQL

Security checks for vulnerabilities and agentic risk

Overview

This test-MySQL skill is mostly coherent, but it needs Review because its helper can modify database data and its read-only safeguard is bypassable.

Install only for disposable or well-scoped test databases. Use least-privilege MySQL credentials, preferably server-enforced read-only credentials for normal use, avoid passing passwords on the command line, and do not rely on the helper's read-only check as a security boundary until the CTE bypass and TLS handling are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mysql_query.py:14
Finding

Read-Only Enforcement Can Be Bypassed with CTE-Prefixed Write Statements

Content
View full analysis

Vulnerability Details

File Location: scripts/mysql_query.py, lines 14-21, 51-55, and 193-196
Vulnerability Type: Incorrect SQL statement classification
Risk Level: High

Vulnerable Code

python
READ_PREFIXES = (
    "select",
    "show",
    "desc",
    "describe",
    "explain",
    "with",
)
python
def is_read_only(sql: str) -> bool:
    cleaned = compact_sql(sql).lower()
    if not cleaned:
        return False
    return cleaned.startswith(READ_PREFIXES)
python
if not args.allow_write:
    for statement in iter_statements(sql):
        if not is_read_only(statement):
            raise SystemExit("Refusing non-read SQL without --allow-write.")

Technical Analysis

The script classifies SQL as read-only solely by checking its initial keyword. Every statement beginning with WITH is accepted, even though MySQL permits common table expressions to prefix modifying statements such as UPDATE and DELETE.

The separate blocked-pattern validation does not reliably prevent this bypass. Its DELETE pattern only rejects an apparently unconstrained deletion, while its UPDATE pattern only rejects updates without a detected WHERE clause. A constrained modifying statement beginning with WITH can therefore pass both controls without --allow-write.

For example, the following statement is classified as read-only:

sql
WITH ids AS (SELECT id FROM target WHERE id = 1)
DELETE FROM target WHERE id IN (SELECT id FROM ids)

The application-level check is not a security boundary because it does not parse the effective statement following the CTE.

Attack Path

  1. An attacker, untrusted input source, or mistaken operator supplies SQL beginning with WITH.
  2. The CTE is followed by a constrained UPDATE or DELETE.
  3. is_read_only() accepts the statement because its first keyword is WITH.
  4. The broad-statement regular express ...[truncated 997 chars]
Remediation
View remediation

Remediation Suggestions

  • Replace prefix-based detection with a maintained MySQL-aware parser that resolves the effective statement type after any CTE.
  • Explicitly reject CTE-prefixed INSERT, UPDATE, DELETE, REPLACE, DDL, administrative statements, and stored procedure calls in read-only mode.
  • Use a dedicated MySQL account with server-enforced SELECT-only grants for normal query execution.
  • Use separate write-capable credentials only after explicit approval.
  • Set the session or transaction to read-only where supported, while retaining account-level restrictions as the primary control.
  • Do not allow --autocommit in read-only mode unless the statement has been securely classified.
  • Add regression tests for CTE-prefixed UPDATE, DELETE, INSERT, nested comments, mixed case, and multiple statements.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mysql_query.py:86
Finding

MySQL Connections Do Not Require Verified TLS

Content
View full analysis

Vulnerability Details

File Location: scripts/mysql_query.py, lines 86-108
Vulnerability Type: Sensitive information transmitted without enforced authenticated encryption
Risk Level: Medium

Vulnerable Code

python
if driver_name == "pymysql":
    return driver.connect(
        host=host,
        port=port,
        user=user,
        password=password,
        database=database,
        charset="utf8mb4",
        cursorclass=driver.cursors.DictCursor,
        connect_timeout=args.connect_timeout,
        read_timeout=args.read_timeout,
        write_timeout=args.write_timeout,
        autocommit=args.autocommit,
    )

return driver.connect(
    host=host,
    port=port,
    user=user,
    password=password,
    database=database,
    connection_timeout=args.connect_timeout,
    autocommit=args.autocommit,
)

Technical Analysis

Sending credentials and query data to a MySQL server is necessary for the Skill's declared database-query functionality. However, the connection code does not require TLS, supply a trusted certificate authority, or explicitly require server identity verification.

In particular, the PyMySQL connection receives no ssl configuration. The mysql.connector path also does not establish an explicit fail-closed policy requiring certificate and hostname verification. Actual behavior can vary with driver and server configuration, so the script cannot guarantee authenticated encryption.

Consequently, the necessary network transmission exceeds minimum safe privilege and exposure expectations because sensitive credentials and database content may traverse a connection whose confidentiality and peer identity have not been enforced by the helper.

Attack Path

  1. The operator configures a remote MySQL endpoint and invokes the helper.
  2. The helper passes the username, password, SQL statements, and returned data through the selected driver.

...[truncated 986 chars]

Remediation
View remediation

Remediation Suggestions

  • Require TLS for both supported drivers and fail closed if an encrypted connection cannot be established.
  • Accept a trusted CA certificate through a protected configuration mechanism.
  • Require certificate and hostname verification rather than encryption without peer authentication.
  • For PyMySQL, provide an ssl configuration with the trusted CA and certificate verification enabled.
  • For mysql.connector, explicitly configure CA validation and ssl_verify_cert/ssl_verify_identity as supported by the deployed version.
  • Avoid options that silently downgrade to plaintext.
  • Document certificate provisioning and rotation without placing private credentials in the repository.
  • Verify the negotiated cipher and TLS status after connection when the driver exposes that information.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/mysql_query.py:160
Finding

Database Password Can Be Exposed Through Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/mysql_query.py, lines 74-76 and 160-165
Vulnerability Type: Secret exposure through process arguments and shell history
Risk Level: Low

Vulnerable Code

python
user = args.user or get_env("TEST_MYSQL_USER")
password = args.password or get_env("TEST_MYSQL_PASSWORD")
database = args.database or get_env("TEST_MYSQL_DATABASE")
python
parser.add_argument("--host")
parser.add_argument("--port")
parser.add_argument("--user")
parser.add_argument("--password")
parser.add_argument("--database")

Technical Analysis

The helper permits a database password to be supplied through --password. Command-line arguments can be recorded in shell history, process inspection interfaces, diagnostic tools, job telemetry, audit systems, or wrapper logs.

This conflicts with the Skill's documented requirement to treat database credentials as secrets. Environment variables are already supported and reduce some exposure, although a protected secret manager, option file, or interactive prompt is preferable where available.

Attack Path

  1. An operator invokes the helper with --password secret-value.
  2. The full command is retained in shell history or exposed in the process argument list while the command is running.
  3. A local user, monitoring agent, support bundle, or log collector obtains the argument.
  4. The observer reuses the password to authenticate to the MySQL server, subject to network controls and account restrictions.

Impact Assessment

Disclosure grants no more privileges than the affected MySQL account already possesses, but it may enable unauthorized reading or modification of every database object accessible to that account. The impact depends on the account's grants, source-host restrictions, password reuse, and network reachability.

No hardcoded password was found in the repository.

Remediation
View remediation

Remediation Suggestions

  • Remove the --password command-line option.
  • Use an interactive getpass() prompt when a password is not available through an approved secret source.
  • Prefer a secret manager, protected MySQL option file, or narrowly scoped environment injection mechanism.
  • Ensure option files have restrictive filesystem permissions.
  • Avoid printing, logging, or including credentials in exception messages.
  • Document that database passwords must never be placed in shell commands, scripts, chat messages, or generated artifacts.
  • Rotate any credential known to have been used through command-line arguments if local history or telemetry may have retained it.
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill instructs the agent to read project files and environment variables to discover database connection details, but it does not declare any explicit tool scope such as allowed-tools or permissions. That mismatch weakens least-privilege controls: a runtime may grant broader file/env access than reviewers expect, increasing the chance of unintended secret exposure or use of sensitive local context during database operations.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script enforces read-only behavior by default, but a single flag (--allow-write) disables that protection and permits arbitrary write statements against the configured test database. In the context of a troubleshooting skill, this creates a real integrity risk because it exceeds the advertised 'controlled low-risk correction' scope and provides no guardrails on which tables or write operations are allowed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Write execution can be enabled without any secondary confirmation, approval check, or interactive warning, so an operator or upstream agent can modify data immediately once --allow-write is set. Even in a test environment, this can corrupt validation data, invalidate investigations, and cause misleading results for downstream testing or release decisions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The display name and short description are presented in Chinese, while the default prompt is in English. This imposes inconsistent language behavior without any explicit user opt-in or documented locale choice, which can conflict with organizational language/locale policy requirements.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The top-level docstring describes the tool as using read-only defaults, which suggests a read-focused utility. However, the code includes an --allow-write path that executes write statements and commits them, so the documentation understates the actual side effects and can mislead users about the tool's capabilities.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.