Back to skill

Security audit

mysql-aiops

Security checks for vulnerabilities and agentic risk

Overview

The skill is transparent about its MySQL DBA purpose, but it exposes live database write actions without a built-in MCP approval or read-only control.

Use this only with a dedicated least-privilege MySQL/MariaDB account at first. Keep it read-only unless you intentionally want the agent to make operational changes, restrict the database account by host and TLS, replace all placeholder passwords, protect MYSQL_AIOPS_MASTER_PASSWORD, and treat MCP write access as production change authority.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:191
Finding

MCP write operations lack an enforced authorization and approval gate

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:191-202
Vulnerability Type: Missing authorization enforcement for state-changing MCP operations
Risk Level: High

Vulnerable documentation segment:

text
## Governance & Safety

The skill delivers reads and writes and records them; it does **not** decide whether a write is
permitted. That is your agent's judgement, or the permission of the account you connect it with
(point it at a MySQL/MariaDB account granted only SELECT / PROCESS / REPLICATION CLIENT and no
write privileges (no INSERT/UPDATE/DELETE/DDL) — writes then fail at the server). There is no
read-only switch, policy file, or approval gate.

- **Audit is the guarantee, and it is not bypassable.** Every operation — MCP and CLI alike — is logged to `~/.mysql-aiops/audit.db` (relocatable via `MYSQL_AIOPS_HOME`): params, result, status, duration, and the risk tier. The CLI writes the same row the MCP path does.
- `MYSQL_AUDIT_APPROVED_BY` / `MYSQL_AUDIT_RATIONALE` are optional annotations recorded on the audit row (who/why); they are never required and never block.
- **Runaway guard** — a safety backstop, not authorization: the same call looped in a tight window trips a circuit breaker. Disable with `MYSQL_RUNAWAY_MAX=0`.
- Writes support `--dry-run` / `dry_run=True` and double confirmation at the CLI.

Related documentation in references/capabilities.md:58-69 identifies write-capable MCP tools including kill_session, kill_query, drop_index, optimize_table, analyze_table, create_index, set_global_variable, and reset_query_stats.

Technical Analysis

The Skill explicitly states that no read-only switch, policy file, or approval gate is enforced. Double confirmation is described only for the CLI layer, while the same write operations are exposed as MCP tools. Consequently, an MCP caller can request a state-changing operation with dry_run=False without presenting an opera ...[truncated 2364 chars]

Remediation
View remediation

Remediation Suggestions

  • Enforce authorization within every MCP write handler rather than relying on agent judgment or database privileges alone.
  • Make MCP write operations default to dry-run and require an explicit transition to execution.
  • Require a short-lived, cryptographically strong approval token bound to the exact target, operation, normalized parameters, and expiration time.
  • Reject execution if any approved parameter changes between preview and execution.
  • Apply confirmation requirements consistently to both CLI and MCP entry points.
  • Provide and enforce a read-only operating mode that prevents registration or execution of write tools.
  • Default onboarding to a least-privilege read-only database account and require an explicit administrative step to enable maintenance privileges.
  • Keep audit logging and runaway protection as defense-in-depth controls, but do not treat them as substitutes for preventive authorization.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/cli-reference.md (reported line 11)May include surrounding context.

bash
mysql-aiops init                      # interactive onboarding wizard
mysql-aiops doctor [--skip-auth]      # config + secrets + connectivity + flavor + perf-schema + replica role
mysql-aiops overview [--target <t>]   # one-shot server health snapshot
mysql-aiops mcp                       # start the MCP server (stdio transport)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/setup-guide.md (reported line 114)May include surrounding context.

bash
mysql-aiops init                      # interactive onboarding wizard
mysql-aiops doctor [--skip-auth]      # config + secrets + connectivity + flavor + perf-schema + replica role
mysql-aiops overview [--target <t>]   # one-shot server health snapshot
mysql-aiops mcp                       # start the MCP server (stdio transport)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/cli-reference.md (reported line 22)May include surrounding context.

mysql-aiops secret set [--value ] # store password (hidden prompt if no --value) mysql-aiops secret list # names only — values never shown mysql-aiops secret rm mysql-aiops secret migrate # import legacy plaintext .env (MYSQL__PASSWORD) mysql-aiops secret rotate-password # re-encrypt under a new master password

text

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The skill explicitly persists sensitive operational state locally: an audit database plus encrypted credential storage, and it also supports a legacy plaintext password environment variable fallback. Persistent local storage of credentials and detailed audit records increases the blast radius of host compromise, accidental disclosure, or insecure filesystem permissions, especially in MCP/CI environments where the master password may also be supplied via environment variable.

Content

Scanner excerpt · SKILL.md (reported line 23)May include surrounding context.

md
metadata: {"openclaw":{"requires":{"anyBins":["mysql-aiops","uvx"]},"optional":{"env":["MYSQL_AIOPS_CONFIG","MYSQL_AIOPS_MASTER_PASSWORD"]},"homepage":"https://github.com/AIops-tools/MySQL-AIops","emoji":"🐬","os":["macos","linux"]}}
compatibility: >
  Standalone, self-governed MySQL/MariaDB DBA operations. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency. Connects via PyMySQL (30s timeouts) and reads information_schema / performance_schema; the server flavor (mysql vs mariadb) is detected from version() and flavor-dependent statements branch (SHOW REPLICA STATUS vs SHOW SLAVE STATUS; performance_schema.data_lock_waits vs information_schema.innodb_lock_waits).
  All write operations are audited to a local SQLite DB under ~/.mysql-aiops/ (relocatable via MYSQL_AIOPS_HOME).
  Credentials: the MySQL account password is stored ENCRYPTED in ~/.mysql-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'mysql-aiops init' to onboard, or 'mysql-aiops secret set <target>' to add one. The store is unlocked by a master password from MYSQL_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var MYSQL_<TARGET_NAME_UPPER>_PASSWORD is still honoured as a fallback with a deprecation warning (migrate with 'mysql-aiops secret migrate'). The password is passed to pymysql.connect at connect time and held only in memory; it is never logged or echoed.
  SQL safety: all values are bound query parameters; the few identifiers that cannot be parameterised (schema/table/index/column/variable names, ORDER BY columns) are validated against a strict identifier charset / allow-lists and backtick-quoted before interpolation. EXPLAIN rejects multi-statement input; the drop_index undo replay path is shape-gated to CREATE [UNIQUE] INDEX statements.
  State-changing operations require double confirmation at the CLI la
...[truncated 25 chars]

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 119)May include surrounding context.

md
check you are not duplicating an index that already exists (a redundant index costs
   writes and buys nothing).
7. `mysql-aiops remediate create-index <table> <col> --name idx_x --dry-run` → prints
   the exact DDL; re-run without `--dry-run` (double-confirm). The write is reversible
   and records an inverse `drop_index` undo descriptor.
8. Re-run `mysql-aiops query explain "<sql>"` and `analyze slow-query` to prove the plan
   changed and the digest dropped.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · references/cli-reference.md (reported line 11)May include surrounding context.

bash
mysql-aiops init                      # interactive onboarding wizard
mysql-aiops doctor [--skip-auth]      # config + secrets + connectivity + flavor + perf-schema + replica role
mysql-aiops overview [--target <t>]   # one-shot server health snapshot
mysql-aiops mcp                       # start the MCP server (stdio transport)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · references/setup-guide.md (reported line 114)May include surrounding context.

bash
mysql-aiops init                      # interactive onboarding wizard
mysql-aiops doctor [--skip-auth]      # config + secrets + connectivity + flavor + perf-schema + replica role
mysql-aiops overview [--target <t>]   # one-shot server health snapshot
mysql-aiops mcp                       # start the MCP server (stdio transport)

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

The setup guide creates a persistent MySQL account accessible from '%' with a placeholder password change-me, which materially increases the chance of insecure deployment if copied verbatim. A broadly reachable service account with PROCESS and replication visibility can expose server activity and metadata, and may become an entry point if weak credentials are left unchanged.

Content

Scanner excerpt · references/setup-guide.md (reported line 18)May include surrounding context.

performance_schema. A least-privilege monitoring account works for the reads:

sql
CREATE USER 'aiops'@'%' IDENTIFIED BY 'change-me';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'aiops'@'%';
GRANT SELECT ON performance_schema.* TO 'aiops'@'%';
-- performance_schema must be ON (default on MySQL 8.x) for query stats

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The guide recommends exporting the master password via an environment variable for CI/cron use without warning that environment variables are commonly exposed through shell history, process inspection, inherited child processes, crash dumps, and CI logs. Because this password unlocks the encrypted credential store, disclosure can expose all stored database secrets for configured targets.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/setup-guide.md (reported line 64)May include surrounding context.

md
- The password is **never** written to disk in plaintext. It lives only in
  `~/.mysql-aiops/secrets.enc`, encrypted with Fernet (AES-128-CBC + HMAC),
  the key derived from your master password via scrypt. Only a per-store random
  salt and the ciphertext are on disk (chmod 600); the master password itself is
  never stored.
- A legacy plaintext env var `MYSQL_<TARGET_NAME_UPPER>_PASSWORD` is still
  honoured as a fallback with a deprecation warning — migrate with

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/setup-guide.md (reported line 94)May include surrounding context.

md
strict identifier charset / allow-lists and backtick-quoted before
  interpolation; anything that is not a plain identifier is rejected.
- `EXPLAIN` rejects multi-statement input (an embedded `;` is refused); the
  `drop_index` undo replay is shape-gated to `CREATE [UNIQUE] INDEX` statements.

## Governance harness state

Static analysis

No suspicious patterns detected.