Back to skill

Security audit

Dev Machine Database

Security checks for vulnerabilities and agentic risk

Overview

The skill is meant for database lookup, but it ships powerful hardcoded database access and unsafe command construction that could expose or alter internal data.

Install only in an environment where you control the datax host and the MySQL instance. Before use, rotate the exposed password, remove hardcoded credentials, replace root with a dedicated read-only account, enforce an allowlist for SELECT/SHOW/DESCRIBE-style operations, avoid embedding SQL in SSH shell strings, and require confirmation before sharing database results to Feishu.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
query_db.py:13
Finding
Hardcoded MySQL Root Credentials Exposed in Source and Process Arguments<![CDATA[ ## Vulnerability Details **File Location**: `query_db.py`, lines 13–14 and 38 **Vulnerability Type**: Hardcoded secret and plaintext credential exposure **Risk Level**: Critical ### Vulnerable Code ```python MYSQL_USER = "root" MYSQL_PASSWORD = "123456" ``` ```python cmd = f'docker exec {MYSQL_CONTAINER} mysql -u{MYSQL_USER} -p{MYSQL_PASSWORD} {database} -e "{sql}"' ``` ### Technical Analysis The script embeds a plaintext MySQL root password directly in source code. Anyone with access to the project, source archives, backups, or copied logs can recover the credential. The password is also inserted into the command-line arguments passed to `docker exec` and the MySQL client. Depending on the remote system configuration, command arguments may be visible through process inspection, monitoring systems, diagnostic output, or audit logs. Because the associated database user is `root`, disclosure of this credential has substantially greater consequences than disclosure of a narrowly scoped application credential. ### Attack Path 1. An attacker obtains read access to the project, a source archive, a backup, or output containing the constructed command. 2. The attacker extracts the hardcoded username and password. 3. The attacker identifies an accessible MySQL endpoint or gains command access to the configured development host. 4. The attacker authenticates using the recovered root credential. 5. The attacker accesses any database objects available to the MySQL root account. ### Impact Assessment If the credential is valid, an attacker could obtain full administrative access to the MySQL instance. The potential scope includes disclosure, modification, and deletion of data across all accessible databases, account or privilege changes, and interference with database availability. The exact network reachability of MySQL is not established by the reviewed files, but local access through the configured development host is explicitly part of the skill's i ...[truncated 24 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Rotate the exposed password immediately and investigate whether it has appeared in repositories, logs, backups, or process-monitoring records. 2. Remove all credentials from source code and repository history. 3. Store secrets in an approved secret manager or a protected credential file with restrictive permissions. 4. Avoid passing passwords as command-line arguments. Use a protected MySQL option file, secret mount, or another mechanism that does not expose the password in process arguments. 5. Replace the root account with a dedicated, read-only service account restricted to the required schema and operations. 6. Add automated secret scanning to source-control and CI workflows. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
query_db.py:13
Finding
Database Queries Execute with Unnecessary Root Privileges<![CDATA[ ## Vulnerability Details **File Location**: `query_db.py`, lines 13 and 38 **Vulnerability Type**: Excessive database privileges and least-privilege violation **Risk Level**: High ### Vulnerable Code ```python MYSQL_USER = "root" ``` ```python cmd = f'docker exec {MYSQL_CONTAINER} mysql -u{MYSQL_USER} -p{MYSQL_PASSWORD} {database} -e "{sql}"' ``` ### Technical Analysis The documented purpose of the skill is to perform read-only database inspection, such as listing tables, describing schemas, selecting rows, and counting records. These operations do not require a MySQL root account. Nevertheless, every generated query is executed as `root`. This removes an important defense boundary: any SQL injection, unintended statement, or misuse of the query helper receives the full authority granted to the database administrator instead of being constrained to read-only access. The source code does not enforce the documented authorization restriction at the database account level. ### Attack Path 1. An attacker or unintended caller supplies a malicious query or manipulates a query-building parameter. 2. The generated SQL reaches `query_mysql_docker`. 3. The MySQL client executes the statement using the configured root account. 4. Operations outside the intended read-only scope succeed whenever they are permitted to MySQL root. ### Impact Assessment Successful exploitation may grant access to every schema and table available to the root account. It may also permit data modification, data deletion, DDL operations, and database account or privilege changes. Using root privileges materially increases the impact of the separately identified SQL and command-construction vulnerabilities. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a dedicated MySQL account for this skill. 2. Grant only the minimum required permissions, normally `SELECT` and narrowly required metadata access on explicitly approved schemas. 3. Deny write operations, DDL, account administration, file access, and access to unrelated databases. 4. Restrict the account to the necessary source host or local container connection. 5. Configure the database session or replica as read-only where operationally possible. 6. Periodically audit grants and test that destructive statements fail at the database authorization layer. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
query_db.py:33
Finding
Remote Shell Command Injection Through Unescaped Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `query_db.py`, lines 20–24 and 33–41 **Vulnerability Type**: Remote shell command injection **Risk Level**: Critical ### Vulnerable Code ```python result = subprocess.run( ["ssh", DEV_MACHINE, cmd], capture_output=True, text=True, timeout=timeout ) ``` ```python if "LIMIT" not in sql.upper() and sql.strip().upper().startswith("SELECT"): sql = f"{sql.rstrip(';')} LIMIT {limit}" cmd = f'docker exec {MYSQL_CONTAINER} mysql -u{MYSQL_USER} -p{MYSQL_PASSWORD} {database} -e "{sql}"' returncode, stdout, stderr = ssh_command(cmd) ``` Parameters incorporated into `sql` are also constructed without escaping: ```python return query_mysql_docker(f"DESC {table_name}", database) ``` ```python sql = f"SELECT {columns} FROM {table_name}" if where: sql += f" WHERE {where}" return query_mysql_docker(sql, database, limit) ``` ### Technical Analysis Although the local `subprocess.run` call uses an argument list, the third SSH argument is a single command string. SSH sends that string to the remote command interpreter. Consequently, shell syntax inside `cmd` can be interpreted by the remote shell. The SQL value is placed inside double quotes without shell escaping. The database name is also inserted without quoting or validation. Table names, selected columns, and conditions flow into the SQL value through direct string interpolation. A caller able to supply quote characters or shell metacharacters in one of these parameters may terminate the intended argument and introduce an additional remote shell operation. The local argument-list form does not prevent this because interpretation occurs on the remote host. ### Attack Path 1. An attacker gains control of a database name, SQL string, table name, column expression, or condition passed to the helper. 2. The attacker includes syntax that terminates or alters the double-quoted SQL argument and introduces remote shell syntax. 3. The application c ...[truncated 931 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not assemble a remote shell command by concatenating user-controlled values. 2. Pass SQL through standard input or a protected temporary input channel rather than embedding it in a shell command. 3. If SSH command execution remains necessary, use a fixed remote wrapper with a constrained interface instead of forwarding arbitrary command text. 4. Strictly allowlist database, table, and column identifiers using known schema metadata; do not accept shell-special characters. 5. Parse and validate query conditions structurally rather than accepting raw condition strings. 6. Use robust argument quoting designed specifically for the remote shell if a shell cannot be eliminated, while treating quoting as defense in depth rather than the primary control. 7. Run the SSH connection under a dedicated account restricted to the required command, host, container, and database operation. 8. Add tests covering quotes, command substitutions, separators, redirections, and newline characters to verify that they cannot become remote shell syntax. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
query_db.py:31
Finding
SQL Injection and Failure to Enforce the Documented Read-Only Policy<![CDATA[ ## Vulnerability Details **File Location**: `query_db.py`, lines 31–34 and 47–61 **Vulnerability Type**: SQL injection and unrestricted SQL execution **Risk Level**: Critical ### Vulnerable Code ```python def query_mysql_docker(sql, database=DATABASE, limit=50): if "LIMIT" not in sql.upper() and sql.strip().upper().startswith("SELECT"): sql = f"{sql.rstrip(';')} LIMIT {limit}" ``` ```python def show_tables(database=DATABASE): return query_mysql_docker(f"SHOW TABLES", database) def desc_table(table_name, database=DATABASE): return query_mysql_docker(f"DESC {table_name}", database) def select_data(table_name, columns="*", where="", database=DATABASE, limit=50): sql = f"SELECT {columns} FROM {table_name}" if where: sql += f" WHERE {where}" return query_mysql_docker(sql, database, limit) def count_rows(table_name, database=DATABASE): return query_mysql_docker(f"SELECT COUNT(*) FROM {table_name}", database, 1) ``` ### Technical Analysis Raw SQL fragments and identifiers are assembled through string interpolation. No parameter binding, identifier allowlist, SQL parser, or single-statement validation is used. The `LIMIT` logic is not a read-only security control. It only appends a limit to input beginning with `SELECT` when the substring `LIMIT` is absent. It does not reject write operations, DDL, administrative statements, multiple statements, or malicious expressions. The generic `query_mysql_docker` function therefore accepts arbitrary SQL. Likewise, `table_name`, `columns`, and `where` are inserted directly into SQL. Parameterized values are not used, and no validation ensures that an identifier is a legitimate table or column. This contradicts the skill documentation's claim that only read-only operations are executed. ### Attack Path 1. A caller supplies a crafted table name, column expression, condition, or direct SQL string through an integration that invokes these helpers. 2. The application con ...[truncated 997 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the generic arbitrary-SQL execution interface from user-facing or agent-controlled flows. 2. Permit only explicitly defined operations such as list tables, describe an approved table, select approved columns, and count rows. 3. Validate database, table, and column identifiers against strict allowlists derived from an approved schema. 4. Represent filters as structured fields and operators, then bind filter values through a database driver that supports parameterized queries. 5. Use a SQL parser to require exactly one approved read-only statement and reject comments, multiple statements, DDL, DML, administrative commands, and unsafe functions. 6. Enforce maximum row counts independently of user-provided SQL. 7. Execute all queries through a dedicated read-only database account so that validation failure cannot become a write compromise. 8. Add negative tests for unauthorized statements, injected predicates, unions, subqueries, comments, and statement separators. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Missing User Warnings

High
Confidence
96% confidence
Finding
The skill explicitly supports querying user-related data and later states results may be sent to Feishu, but it does not warn about privacy, data minimization, or outbound data transfer. This creates a real risk of exfiltrating sensitive personal or business data from an internal database into a chat system without informed user confirmation or policy checks.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The module is presented as a database query tool, but it can execute arbitrary SQL, including INSERT, UPDATE, DELETE, DROP, and administrative statements, against a production-like remote MySQL instance using root credentials. In this context, the mismatch is dangerous because callers may assume read-only behavior while the code permits destructive or privilege-altering operations.

Missing User Warnings

High
Confidence
99% confidence
Finding
The code hardcodes MySQL root credentials directly in source, exposing a highly privileged secret to anyone with file access and encouraging reuse of insecure defaults. In this context, compromise of the script or repository immediately grants broad database access and combines with arbitrary SQL execution to enable full data loss or theft.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The trigger phrases are broad and colloquial, making accidental invocation more likely in normal conversation. In this context, accidental activation can lead to unintended access to an internal development host and database, which is more sensitive than a harmless content-generation action.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The skill claims it is read-only and only executes SELECT statements, but the documented examples and workflow include non-SELECT operations such as SHOW and DESC. This mismatch is dangerous because agents or users may rely on the safety claim and permit broader SQL execution than intended, weakening guardrails around database access.

Skill Enumeration

Medium
Category
Agent Snooping
Content
## 相关文件

- 技能位置:`~/.openclaw/workspace/skills/dev-machine-database/SKILL.md`
- 脚本位置:`~/.openclaw/workspace/skills/dev-machine-database/query_db.py`
- 配置位置:`~/.openclaw/workspace/TOOLS.md` (开发机配置)
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The skill includes a generic SSH execution primitive, not just database access, which materially broadens the attack surface. Given that command strings are composed from variables and SQL text, any injection flaw or future feature expansion could turn this into arbitrary command execution on the remote development machine.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
This code executes SSH commands and remotely runs `docker exec`/`mysql` against a development machine, which can access and expose database contents. Although the functions have internal docstrings, there is no user-facing warning, confirmation prompt, or disclosure that remote commands will be executed and database data retrieved.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def ssh_command(cmd, timeout=30):
    """执行 SSH 命令"""
    try:
        result = subprocess.run(
            ["ssh", DEV_MACHINE, cmd],
            capture_output=True,
            text=True,
Confidence
93% confidence
Finding
The subprocess call itself is not shell=True, but it forwards a fully attacker-controllable remote command string to SSH, which is then interpreted by the remote shell. Because higher-level functions interpolate SQL, table names, and database names directly into that command, this creates a command-injection path on the remote host and extends the tool's power beyond simple database queries.

Natural-Language Policy Violations

Low
Confidence
79% confidence
Finding
The module description and user-facing messages are presented exclusively in Chinese, which can amount to a language/locale policy issue when no user opt-in or alternative is offered. There is no indication that this skill is intentionally restricted to a Chinese-speaking or region-specific audience.

Static analysis

No suspicious patterns detected.