Back to skill

Security audit

Database Skill

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate database assistant, but it needs review because it can use cloud database credentials, run powerful database operations, terminate sessions, and persist analyzed data with weak safeguards.

Review this skill before installing in a production or admin context. Use least-privilege, preferably read-only credentials for analysis; disable or tightly control update_env, execute_sql, and kill_process; require explicit human confirmation for session termination and database changes; and clean or isolate local DuckDB/temp/workspace outputs that may contain sensitive data.

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
scripts/toolbox.py:657
Finding
Read-only SQL interface does not enforce read-only statements<![CDATA[ ## Vulnerability Details **File Location**: `scripts/toolbox.py:657-688` **Vulnerability Type**: Missing server-operation input validation **Risk Level**: High ### Vulnerable Code ```python def execute_sql( client: ToolboxClient, sql: str, instance_id: Optional[str] = None, database: Optional[str] = None, ) -> dict[str, Any]: try: if not sql: return _error("sql parameter cannot be empty") prep = _prepare(client, instance_id=instance_id, database=database) if not prep["ok"]: return prep["error"] p, ctx = prep["params"], prep["ctx"] if not p["database"]: return _error("database parameter is missing", {"missing": ["database"]}, context=ctx) req = { "instance_id": p["instance_id"], "instance_type": p["instance_type"], "database": p["database"], "commands": sql, "time_out_seconds": 60, } result = client.dbw.execute_sql(req) ``` The displayed error strings have been translated into English; the executable control flow is unchanged. ### Technical Analysis The function is documented and presented to the Agent as a read-only interface, but it does not inspect or classify the supplied SQL. Any non-empty string is copied directly into the `commands` field and sent to the remote `ExecuteSQL` operation. Instructions in `SKILL.md` tell the Agent not to use this function for DML or DDL, but prompt-level guidance is not a security boundary. Direct Python callers, command-line callers, compromised prompts, or later changes to Agent behavior can bypass those instructions. The implementation does not reject: - `INSERT`, `UPDATE`, or `DELETE` - `CREATE`, `ALTER`, or `DROP` - Administrative statements - Multiple statements separated by delimiters - Statements obscured by comments or dialect-specific syntax Whether a particular destructive statement completes also depends on database ...[truncated 1124 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse SQL with a dialect-aware parser before sending it to the API. 2. Require exactly one statement. 3. Allow only explicitly read-only statement types such as `SELECT`, `SHOW`, and `EXPLAIN`. 4. Reject DML, DDL, transaction-control, privilege-management, file-access, and administrative statements. 5. Reject stacked statements and ambiguous parse results. 6. Do not rely on keyword-prefix checks, because comments, common table expressions, and dialect-specific syntax can bypass them. 7. Enforce the same restrictions in the upstream DBW API as defense in depth. 8. Add tests covering mixed case, comments, stacked statements, writable common table expressions, and dialect-specific write operations. 9. Use separate credentials with database-level read-only permissions for this interface. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/toolbox.py:927
Finding
SQL injection in the PostgreSQL table-metadata fallback<![CDATA[ ## Vulnerability Details **File Location**: `scripts/toolbox.py:927-945` **Vulnerability Type**: SQL injection through unescaped metadata parameters **Risk Level**: High ### Vulnerable Code ```python def _pg_get_table_info( client: ToolboxClient, table: str, instance_id: str, database: str, schema: Optional[str], ctx: dict, ) -> dict[str, Any]: schema = schema or "public" sql = ( f"SELECT column_name, data_type, character_maximum_length, " f"is_nullable, column_default, " f"col_description((table_schema||'.'||table_name)::regclass, ordinal_position) as comment " f"FROM information_schema.columns " f"WHERE table_schema = '{schema}' AND table_name = '{table}' " f"ORDER BY ordinal_position" ) result = execute_sql(client, sql=sql, instance_id=instance_id, database=database) ``` ### Technical Analysis The `schema` and `table` arguments are inserted directly into SQL string literals. The implementation does not escape quotation marks, bind parameters, validate identifiers, or reject comments and statement delimiters. Although these values represent metadata names, they remain caller-controlled inputs to the public `get_table_info()` API. A crafted value can terminate the quoted literal and modify the query predicate. If the DBW execution layer accepts multiple statements, the same flaw may also permit stacked SQL statements. This issue is compounded by the absence of read-only validation in `execute_sql()`. ### Attack Path 1. An attacker supplies a crafted PostgreSQL table or schema argument containing a quotation mark and injected SQL syntax. 2. `get_table_info()` selects `_pg_get_table_info()` for PostgreSQL. 3. The attacker-controlled value is interpolated into the `WHERE` clause. 4. The resulting SQL is passed to `execute_sql()` without validation. 5. At minimum, the attacker can modify the metadata query logic and expose metadata outside the intended table ...[truncated 625 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use parameterized SQL for `schema` and `table` values when the execution API supports bound parameters. 2. If binding is unavailable, implement a dedicated SQL-literal quoting function and verify it against PostgreSQL escaping rules. 3. Apply a conservative identifier policy where business requirements permit it, such as rejecting control characters, comments, null bytes, and statement delimiters. 4. Do not construct SQL by interpolating raw caller input. 5. Add the read-only and single-statement enforcement described for `execute_sql()`. 6. Add regression tests using quotation marks, comment tokens, semicolons, Unicode edge cases, and valid quoted PostgreSQL identifiers. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/multi_source_analyzer.py:32
Finding
Sensitive analysis data persists in a predictable shared temporary database<![CDATA[ ## Vulnerability Details **File Location**: `scripts/multi_source_analyzer.py:32-106` **Vulnerability Type**: Predictable temporary storage and cross-session data residue **Risk Level**: Medium ### Vulnerable Code ```python DB_PATH = os.path.join(tempfile.gettempdir(), 'multi_source_analyzer.duckdb') ``` ```python def __init__(self): if os.path.exists(DB_PATH): self._duck_conn = duckdb.connect(database=DB_PATH, read_only=False) else: self._duck_conn = duckdb.connect(database=DB_PATH) self._sources: Dict[str, DataSource] = {} atexit.register(self._cleanup) def _cleanup(self): pass ``` ```python def register_dataframe(self, name: str, df: pd.DataFrame) -> DataSource: source = DataSource(name=name, source_type='dataframe') source.set_dataframe(df) self._sources[name] = source self._duck_conn.execute(f"CREATE OR REPLACE TABLE {name} AS SELECT * FROM df") return source ``` ### Technical Analysis Every analyzer instance uses the same predictable file in the operating system temporary directory. Imported CSV, Excel, JSON, Parquet, and database-derived DataFrame content is copied into persistent DuckDB tables. The registered exit handler intentionally performs no cleanup. Consequently, data survives process termination and can be reused by later runs. The implementation also does not create a private per-run directory, explicitly enforce restrictive permissions, or verify that the path is not a symbolic link. This design creates the following risks: - Sensitive data remains on disk after the analysis completes. - Independent users or jobs sharing the runtime may collide with the same database. - A later analysis session may observe stale tables from an earlier session. - A local attacker may pre-create or manipulate the predictable path where filesystem permissions permit it. ### Attack Path 1. A victim imports a sensitive file or registers database query results. 2. `register_dataframe()` m ...[truncated 918 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use an in-memory DuckDB database by default. 2. If persistence is required, create a random per-run directory with `tempfile.mkdtemp()` and mode `0700`. 3. Create the database with a randomized filename and enforce owner-only permissions. 4. Remove the database and containing directory in `close()`, the exit handler, and exception paths. 5. Require explicit user opt-in before preserving analysis state across runs. 6. Do not reuse a process-global database path across users or jobs. 7. Detect and reject symbolic links and unexpected existing file types before opening persistent storage. 8. Document the retention policy and provide a reliable secure cleanup operation. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/multi_source_analyzer.py:100
Finding
DuckDB SQL injection through unquoted source names<![CDATA[ ## Vulnerability Details **File Location**: `scripts/multi_source_analyzer.py:100-156` **Vulnerability Type**: SQL injection through dynamic identifiers **Risk Level**: Medium ### Vulnerable Code ```python def register_dataframe(self, name: str, df: pd.DataFrame) -> DataSource: source = DataSource(name=name, source_type='dataframe') source.set_dataframe(df) self._sources[name] = source self._duck_conn.execute(f"CREATE OR REPLACE TABLE {name} AS SELECT * FROM df") return source ``` ```python def query(self, sql: str, limit: int = 100) -> pd.DataFrame: result = self._duck_conn.execute(sql).fetchdf() if limit and len(result) > limit: return result.head(limit) return result def describe(self, name: str) -> pd.DataFrame: return self.query(f"DESCRIBE {name}") def preview(self, name: str, n: int = 5) -> pd.DataFrame: return self.query(f"SELECT * FROM {name} LIMIT {n}") ``` ### Technical Analysis The public `name` value is treated as a SQL identifier but is concatenated into DuckDB statements without validation or identifier quoting. The `n` preview value is also inserted into SQL text when the Python API is used directly. An attacker can provide syntax rather than a table name. Depending on DuckDB statement parsing and the specific call, crafted input can alter the intended statement or introduce additional SQL. Because the analyzer uses a persistent writable database, injected statements can modify or remove tables and affect later sessions. The unrestricted `query()` method also executes arbitrary DuckDB SQL. While advanced querying is part of the analyzer’s purpose, routing externally supplied SQL to this method creates a privileged interface rather than a read-only analysis boundary. ### Attack Path 1. An attacker controls a source name supplied through `register_dataframe()`, `register_file()`, `describe()`, or `preview()`. 2. The value is inserted directly into a DuckDB SQL string. 3. DuckDB p ...[truncated 858 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate source names against a conservative identifier policy. 2. Quote identifiers with a trusted DuckDB-compatible identifier-quoting helper rather than string interpolation. 3. Convert and range-check `n` as an integer before query construction. 4. Separate the ordinary read-only analysis interface from any intentionally unrestricted administrative SQL interface. 5. Parse normal analysis queries and allow only single read-only statements. 6. Disable or restrict dangerous DuckDB features where possible. 7. Run analysis in an isolated per-task database with minimum filesystem permissions. 8. Add tests for quotation marks, semicolons, comments, reserved words, Unicode identifiers, and stacked-statement attempts. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/toolbox.py:559
Finding
Credential updates use a predictable plaintext temporary file<![CDATA[ ## Vulnerability Details **File Location**: `scripts/toolbox.py:559-608` **Vulnerability Type**: Unsafe temporary file handling for secrets **Risk Level**: Medium ### Vulnerable Code ```python def update_env(**kwargs: str) -> dict[str, Any]: allowed_keys = { "VOLCENGINE_ACCESS_KEY", "VOLCENGINE_SECRET_KEY", "VOLCENGINE_REGION", "VOLCENGINE_INSTANCE_ID", "VOLCENGINE_DATABASE", } to_update = {k: v for k, v in kwargs.items() if k in allowed_keys and v} ignored = [k for k in kwargs if k not in allowed_keys] if not to_update: return _error("No valid configuration items to update", {"ignored": ignored}) existing_lines: list[str] = [] if os.path.exists(_ENV_PATH): with open(_ENV_PATH, "r") as f: existing_lines = f.readlines() def _extract_key(line: str) -> Optional[str]: s = line.strip() if not s or s.startswith("#"): return None raw = s[7:] if s.startswith("export ") else s if "=" not in raw: return None return raw.partition("=")[0].strip() updated_keys: set[str] = set() new_lines: list[str] = [] for line in existing_lines: key = _extract_key(line) if key and key in to_update: prefix = "export " if line.strip().startswith("export ") else "" new_lines.append(f'{prefix}{key}="{to_update[key]}"\n') updated_keys.add(key) else: new_lines.append(line) for key, value in to_update.items(): if key not in updated_keys: new_lines.append(f'export {key}="{value}"\n') updated_keys.add(key) if new_lines and not new_lines[-1].endswith("\n"): new_lines[-1] += "\n" tmp_path = _ENV_PATH + ".tmp" with open(tmp_path, "w") as f: f.writelines(new_lines) os.replace(tmp_path, _ENV_PATH) ``` The displayed error string has been translated into English; the executable control flow is unc ...[truncated 1730 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a temporary file in the same directory with `tempfile.mkstemp()` or `NamedTemporaryFile(delete=False)`. 2. Use a randomized filename and exclusive creation. 3. Set the temporary and final files to mode `0600`. 4. Verify that the destination and temporary paths are regular files and not symbolic links. 5. Write through the securely created file descriptor rather than reopening the path. 6. Flush and call `os.fsync()` before atomic replacement. 7. Apply restrictive permissions again after `os.replace()`. 8. Ensure the parent directory is not writable by untrusted users. 9. Prefer a platform secret manager or protected credential store over plaintext `.env` persistence. 10. Add concurrency controls so simultaneous updates cannot overwrite each other. ]]>
Vulnerability Patterns
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (101)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
This mismatch includes undeclared sensitive capabilities such as environment configuration management (`check_env/update_env`) and process termination (`kill_process`). Hidden or under-disclosed credential handling and process-control capabilities are dangerous because users may invoke the skill expecting passive database analysis while the agent can modify secrets or disrupt running sessions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This mismatch includes undeclared sensitive capabilities such as environment configuration management (`check_env/update_env`) and process termination (`kill_process`). Hidden or under-disclosed credential handling and process-control capabilities are dangerous because users may invoke the skill expecting passive database analysis while the agent can modify secrets or disrupt running sessions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
This mismatch includes undeclared sensitive capabilities such as environment configuration management (`check_env/update_env`) and process termination (`kill_process`). Hidden or under-disclosed credential handling and process-control capabilities are dangerous because users may invoke the skill expecting passive database analysis while the agent can modify secrets or disrupt running sessions.

Credential Access

High
Category
Privilege Escalation
Content
凭证通过 `create_client()` 初始化时自动加载(优先级:环境变量 > `skills/.env` 文件)。

### ⚠️ 严禁直接操作 .env 文件

- **绝对禁止**用 Write / Edit / shell 命令直接读写 `.env` 文件
- **绝对禁止**通过 shell 命令(如 `echo $VOLCENGINE_ACCESS_KEY`)检查凭证
Confidence
93% confidence
Finding
The skill explicitly includes credential access and mutation paths via environment loading and `update_env`, even though it warns against direct `.env` manipulation. In an agent environment, any ability to read credential state or write secrets increases the risk of secret mishandling, persistence of attacker-supplied credentials, lateral movement, or unauthorized access to cloud database resources.

Hidden Instructions

High
Category
Prompt Injection
Content
</head>
<body>

<!-- ═══════════ 报告标题 ═══════════ -->
<div class="report-header">
  <p class="report-title">营销渠道 ROI 下钻分析</p>
  <p class="report-subtitle">数据范围:2025-07 ~ 2025-12 | 数据源:MySQL + PostgreSQL + Excel</p>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
</head>
<body>

<!-- ═══════════ 报告标题 ═══════════ -->
<div class="report-header">
  <p class="report-title">营销渠道 ROI 下钻分析</p>
  <p class="report-subtitle">数据范围:2025-07 ~ 2025-12 | 数据源:MySQL + PostgreSQL + Excel</p>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Credential Access

High
Category
Privilege Escalation
Content
instance_id: Optional[str] = None,
        database: Optional[str] = None,
    ):
        # 优先级:构造参数 > OS env > .env > 默认值
        self.region = region or os.environ.get("VOLCENGINE_REGION")
        self.ak = ak or os.environ.get("VOLCENGINE_ACCESS_KEY")
        self.sk = sk or os.environ.get("VOLCENGINE_SECRET_KEY")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
instance_id: Optional[str] = None,
        database: Optional[str] = None,
    ):
        # 优先级:构造参数 > OS env > .env > 默认值
        self.region = region or os.environ.get("VOLCENGINE_REGION")
        self.ak = ak or os.environ.get("VOLCENGINE_ACCESS_KEY")
        self.sk = sk or os.environ.get("VOLCENGINE_SECRET_KEY")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
instance_id: Optional[str] = None,
        database: Optional[str] = None,
    ):
        # 优先级:构造参数 > OS env > .env > 默认值
        self.region = region or os.environ.get("VOLCENGINE_REGION")
        self.ak = ak or os.environ.get("VOLCENGINE_ACCESS_KEY")
        self.sk = sk or os.environ.get("VOLCENGINE_SECRET_KEY")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
instance_id: Optional[str] = None,
        database: Optional[str] = None,
    ):
        # 优先级:构造参数 > OS env > .env > 默认值
        self.region = region or os.environ.get("VOLCENGINE_REGION")
        self.ak = ak or os.environ.get("VOLCENGINE_ACCESS_KEY")
        self.sk = sk or os.environ.get("VOLCENGINE_SECRET_KEY")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
instance_id: Optional[str] = None,
        database: Optional[str] = None,
    ):
        # 优先级:构造参数 > OS env > .env > 默认值
        self.region = region or os.environ.get("VOLCENGINE_REGION")
        self.ak = ak or os.environ.get("VOLCENGINE_ACCESS_KEY")
        self.sk = sk or os.environ.get("VOLCENGINE_SECRET_KEY")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# .env 补全缺失值
        try:
            env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), ".env")
            if os.path.exists(env_path):
                env_vars = self._parse_env_file(env_path)
                self.ak = self.ak or env_vars.get("VOLCENGINE_ACCESS_KEY")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# .env 补全缺失值
        try:
            env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), ".env")
            if os.path.exists(env_path):
                env_vars = self._parse_env_file(env_path)
                self.ak = self.ak or env_vars.get("VOLCENGINE_ACCESS_KEY")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
instance_id: Optional[str] = None,
    database: Optional[str] = None,
) -> ToolboxClient:
    """创建 ToolboxClient,自动从环境变量 / .env 文件加载凭证。

    Args:
        region: 区域(RegionId),默认从 VOLCENGINE_REGION 读取
Confidence
86% confidence
Finding
`create_client` explicitly loads credentials from environment variables and a local `.env` file for operational use. In a hosted agent skill, local secret loading broadens credential exposure and couples the skill to filesystem-based secret management, which is risky if the runtime or adjacent tooling can manipulate or read those values.

Credential Access

High
Category
Privilege Escalation
Content
def update_env(**kwargs: str) -> dict[str, Any]:
    """安全地更新 .env 文件中的配置项。仅修改 VOLCENGINE_ 前缀的 key。"""
    allowed_keys = {
        "VOLCENGINE_ACCESS_KEY", "VOLCENGINE_SECRET_KEY", "VOLCENGINE_REGION",
        "VOLCENGINE_INSTANCE_ID", "VOLCENGINE_DATABASE",
Confidence
95% confidence
Finding
`update_env` modifies stored access credentials and connection defaults in a local `.env` file, which is a high-risk secret-management capability in an agent skill. If invoked unintentionally or maliciously, it can persist attacker-chosen AK/SK or redirect the skill toward unauthorized resources, effectively changing the security boundary for subsequent operations.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
`execute_sql` claims to support only read-only statements, but it forwards arbitrary SQL in `commands` to the backend without any client-side allowlist or parsing enforcement. In an agent setting, this can enable destructive writes, schema changes, or privilege-affecting statements if the model is induced to pass unsafe SQL, especially because nearby APIs also support operational workflows and database administration.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
`kill_process` provides direct database session termination, including batch termination based on filters, which is a destructive operational capability. In an agent-integrated skill, this is dangerous because model errors or adversarial prompts could terminate legitimate transactions or sessions, causing outages, rollback storms, or user-visible disruption.

Missing User Warnings

High
Confidence
98% confidence
Finding
The process-kill path exposes a destructive action with no built-in confirmation, no dry-run default, and support for broad filter-based matching. In an AI-agent workflow, that greatly increases the chance of accidental or manipulated termination of many sessions, making the operational impact immediate and severe.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill describes capabilities that imply environment access, file operations, and network/database interaction, but it does not declare an explicit tool scope or allowlist. In an agent setting, missing scope boundaries increases the chance of over-privileged execution and makes it harder to constrain credential, file, and network access to only what is necessary.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The natural-language instructions throughout the file are exclusively in Chinese and define the assistant behavior in that language, but the skill does not state that Chinese is optional or required for a justified regional/compliance reason. This can violate language or locale policy because it effectively forces one language without user opt-in.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill strongly encourages autonomous execution of database queries and broad data analysis workflows without requiring a privacy/sensitivity check, minimization step, or user warning. In a database operations context, this can easily expose personal, financial, or regulated data through overly broad queries, reports, screenshots, or cross-source analysis.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The entire skill guidance is written as a Chinese-only report-generation specification and presents the reporting behavior in Chinese without any indication that users may choose another language or locale. This creates a natural-language locale policy concern because the skill appears to enforce a specific language by default rather than documenting user opt-in or a justified region-specific constraint.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
The skill instructs use of `npx playwright` without pinning a specific version, which can cause execution of an unexpected or newly published package version at runtime. In an agent skill that may automate report generation, this creates supply-chain and reproducibility risk because behavior can change over time or a compromised upstream release could be pulled implicitly.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
This markdown file contains user-facing natural-language content exclusively in Chinese, including the title, labels, scenarios, and usage instructions. Under the language/locale policy, forcing a specific language without user opt-in or clear justification is a policy concern.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This markdown template is written as a prescriptive skill artifact in Chinese from the title onward, and the usage guidance does not indicate that the language is optional or region-specific. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy violation.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/dbw_client.py:218