Back to skill

Security audit

chat2duckdb

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent DuckDB data-analysis tool, but it exposes broad local SQL, file-read, file-write, and persistence behavior without enough containment.

Install only if you are comfortable giving this skill broad local DuckDB authority over files and writable output paths. Use it on trusted datasets, avoid untrusted SQL or hostile file headers, prefer preview/query output before saving, and treat CSV/Excel exports and persistent DuckDB files as potentially sensitive retained data.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/duckdb_analyzer.py:547
Finding
Unrestricted DuckDB SQL Execution Permits Unauthorized Filesystem and Database Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/duckdb_analyzer.py:547-549` **Vulnerability Type**: Unrestricted execution of user-controlled SQL **Risk Level**: High ### Vulnerable Code ```python if sample_fraction is not None: if "WHERE" in sql.upper(): base_sql, where_part = sql.split("WHERE", 1) sampled_sql = f"{base_sql} WHERE RANDOM() < {sample_fraction} AND {where_part}" else: sampled_sql = f"{sql} WHERE RANDOM() < {sample_fraction}" result = self.conn.execute(sampled_sql).fetchdf() else: result = self.conn.execute(sql).fetchdf() ``` ### Technical Analysis The `--sql` argument is sent directly to `DuckDBPyConnection.execute()` without parsing the statement, enforcing read-only behavior, restricting accessible relations, or rejecting multiple statements. Although the documented purpose is querying the registered `data` table, DuckDB supports operations beyond analytical `SELECT` statements. Depending on the installed DuckDB version and process permissions, SQL can reference local files through table functions, attach databases, create or replace database objects, export data, or write files. The implementation does not reject dangerous SQL features such as: - Multiple statements - `COPY` - `ATTACH` and `DETACH` - `CREATE`, `DROP`, `INSERT`, `UPDATE`, and `DELETE` - `INSTALL` and `LOAD` - External file-reading table functions - Queries against objects other than the intended registered table Consequently, SQL generated from an untrusted request or influenced through prompt injection can exceed the legitimate data-analysis scope. The sampling transformation does not provide protection. It performs string manipulation and then executes the resulting SQL through the same unrestricted interface. ### Attack Path 1. An attacker supplies a natural-language request or direct `--sql` value containing a DuckDB statement that accesses an unintended local resource or performs a write operation. 2. The ...[truncated 1194 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse submitted SQL with a DuckDB-compatible SQL parser rather than validating it with regular expressions. 2. Permit exactly one statement and require its root operation to be a read-only `SELECT`. 3. Restrict referenced relations to an allowlist containing only the registered analysis table. 4. Reject DDL, DML, `COPY`, `ATTACH`, `DETACH`, `INSTALL`, `LOAD`, pragmas, external table functions, and other file or extension operations. 5. Reject semicolon-delimited multiple statements even if the first statement is allowed. 6. Open persistent databases in read-only mode when modification is not explicitly required. 7. Execute the analyzer in a sandbox with access only to the selected input and output paths. 8. Apply operating-system resource limits and narrowly scoped filesystem permissions. 9. Replace the current string-based sampling rewrite with an AST-based transformation or a safe wrapper query after validation. 10. Add security tests demonstrating that local file readers, file writers, extension loading, attachment, DDL, DML, and multiple statements are rejected. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/duckdb_analyzer.py:316
Finding
SQL Injection Through Unquoted Paths, Table Names, and Dataset Column Names<![CDATA[ ## Vulnerability Details **File Location**: `scripts/duckdb_analyzer.py:316-333` and `scripts/duckdb_analyzer.py:407-513` **Vulnerability Type**: SQL injection through unsafe string interpolation **Risk Level**: High ### Vulnerable Code ```python if file_ext == '.csv': self.conn.execute(f"{create_stmt} {self.table_name} AS SELECT * FROM read_csv_auto('{self.file_path}')") elif file_ext == '.json': self.conn.execute(f"{create_stmt} {self.table_name} AS SELECT * FROM read_json_auto('{self.file_path}')") elif file_ext == '.parquet': self.conn.execute(f"{create_stmt} {self.table_name} AS SELECT * FROM read_parquet('{self.file_path}')") elif file_ext in ('.xlsx', '.xls'): read_kwargs = {} if self.excel_sheet: read_kwargs["sheet_name"] = self.excel_sheet excel_df = pd.read_excel(self.file_path, **read_kwargs) excel_df = self._prepare_dataframe_for_registration(excel_df) self.conn.register("__excel_data__", excel_df) self.conn.execute(f"{create_stmt} {self.table_name} AS SELECT * FROM __excel_data__") self.conn.unregister("__excel_data__") else: raise ValueError(f"不支持的文件格式:{file_ext}") schema = self.conn.execute(f"DESCRIBE {self.table_name}").fetchdf() self.columns = list(schema['column_name']) ``` Dataset-derived column names are subsequently interpolated into statistical queries: ```python for col in self.columns: query = f""" SELECT COUNT({col}) as non_null_count, MIN({col}) as min_val, MAX({col}) as max_val, AVG({col}) as avg_val, STDDEV({col}) as stddev_val, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY {col}) as median_val FROM {self.table_name} WHERE {col} IS NOT NULL AND typeof({col}) IN ('INTEGER', 'BIGINT', 'DOUBLE', 'FLOAT') """ result = self.conn.execute(query).fetchone() ``` Other affected query construction includes: ```python total = self.conn.execute(f"SELECT COUNT(*) FROM {self.table_name}").fetchone()[0] for co ...[truncated 2966 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use DuckDB parameter binding for file paths and other literal values wherever the API supports it. 2. Never place filesystem paths directly inside quoted SQL literals. 3. Implement a dedicated identifier-quoting function that surrounds identifiers with double quotes and doubles every embedded double quote. 4. Apply identifier quoting consistently to: - Table names - Column names - Generated aliases - `DESCRIBE`, statistics, and data-quality queries 5. Prefer assigning a fixed internal table name rather than accepting an arbitrary `--table_name`. 6. If custom table names are necessary, validate them against a strict allowlist such as ASCII letters, digits, and underscores, while still quoting them. 7. Map external dataset headers to safe internal identifiers and preserve the original-to-internal mapping for display. 8. Avoid relying on broad `except:` blocks; log failed queries safely and distinguish malformed identifiers from unsupported data types. 9. Combine these changes with the read-only statement policy described in the unrestricted SQL finding. 10. Add regression tests using paths and headers containing apostrophes, double quotes, spaces, reserved words, semicolons, comment markers, Unicode characters, and SQL-like text. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/duckdb_analyzer.py:739
Finding
Spreadsheet Formula Injection in CSV and Excel Exports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/duckdb_analyzer.py:739-749` **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python if args.output: file_ext = os.path.splitext(args.output)[1].lower() if file_ext == '.csv': result.to_csv(args.output, index=False) elif file_ext == '.json': result.to_json(args.output, orient='records', force_ascii=False) elif file_ext == '.parquet': result.to_parquet(args.output, index=False) elif file_ext in ('.xlsx', '.xls'): result.to_excel(args.output, index=False, engine='openpyxl') else: result.to_csv(args.output, index=False) ``` ### Technical Analysis Query results may contain strings controlled by the contents of an untrusted input dataset. Those strings are exported directly to CSV or Excel without detecting spreadsheet formula prefixes. Spreadsheet applications may interpret cells beginning with characters such as the following as formulas rather than literal text: - `=` - `+` - `-` - `@` Leading whitespace, tabs, carriage returns, or other control characters may also be used to obscure a dangerous prefix in some spreadsheet applications. CSV itself does not execute formulas, but opening the generated CSV in spreadsheet software can trigger formula evaluation. Excel output is similarly exposed because formula-like strings may be stored as active formulas depending on the writer's interpretation and the resulting workbook representation. ### Attack Path 1. An attacker places a formula-like string in a CSV, JSON, Parquet, or Excel input cell. 2. The analyzer loads the value and includes it in a query result. 3. The user requests CSV or Excel output. 4. The analyzer exports the value without neutralization. 5. A victim opens the generated file in spreadsheet software. 6. The spreadsheet evaluates the attacker-controlled formula. 7. Depending on spreadsheet security settings and formul ...[truncated 807 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enable safe spreadsheet export by default. 2. Before CSV or Excel export, inspect every string cell after removing or accounting for leading whitespace and control characters. 3. Neutralize cells beginning with `=`, `+`, `-`, or `@`, commonly by prefixing an apostrophe so spreadsheet software treats the content as text. 4. Preserve the original value separately if exact raw-value export is a business requirement. 5. For Excel output, explicitly configure formula-like values as text and apply a text number format. 6. Provide an opt-in raw export mode only when users understand the formula-injection risk. 7. Display a warning when dangerous cells are detected or when raw spreadsheet export is requested. 8. Add tests covering direct prefixes, leading whitespace, tabs, carriage returns, Unicode whitespace, and formulas embedded in every supported input format. 9. Prefer JSON or Parquet when downstream consumers do not require spreadsheet-compatible output. ]]>
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill documents capabilities to export query results and persist data to a DuckDB database, which implies file-write behavior, but it declares no explicit tool scope or permissions boundary. In an agent environment, this can lead to unintended writes to local files or databases without clear authorization controls, increasing the risk of data leakage, overwriting files, or persistence of sensitive data.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The trigger conditions are broad enough to match many generic data-analysis requests, so the skill may activate in situations where the user did not specifically intend SQL execution, file handling, or persistence. Over-broad activation increases the chance of unnecessary access to user data, accidental query execution, or unexpected file output in contexts where safer or narrower tools should be used.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill advertises output export and DuckDB persistence features without a prominent warning that these operations write to disk. Users or higher-level agents may assume analysis is ephemeral, but the skill can create result files or database artifacts that persist sensitive data and may be accessible later.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The export examples encourage saving query results in multiple formats but do not warn that the exported content may include sensitive or regulated data from the source dataset. This omission can lead to inadvertent exfiltration, insecure storage, or broader distribution of confidential records through generated CSV, Excel, JSON, or Parquet files.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The file title and all user-facing guidance are written entirely in Chinese, with no indication that other languages are supported or that the Chinese-only requirement is optional. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is clearly justified.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The manifest describes the skill as applicable to CSV/JSON/Parquet/Excel and related data analysis tasks. This file's FAQ explicitly states that the current version does not directly support Excel files, creating a direct contradiction between the documented capability and the skill's stated intent.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This code file contains natural-language descriptions, help text, and runtime output exclusively in Chinese, beginning with the module docstring and continuing throughout the CLI interface. Under the policy, forcing a specific language without offering a user choice is a natural-language policy violation.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The script can write imported data into a persistent DuckDB database and can also export query results to arbitrary output paths on disk. For a skill presented as a query/analysis tool, these side effects materially expand its capability from transient analysis to local data retention and file creation, which can leak sensitive data or violate least-privilege expectations if users assume in-memory processing only.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
Allowing persistent database/table creation is not inherently malicious, but it is a meaningful expansion of capability beyond simple ad hoc querying. In an agent context, storing imported datasets as real tables can create unintended long-term retention, cross-session data exposure, or accumulation of sensitive data without strong justification or controls.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The natural-language description is written entirely in Chinese and the document consistently assumes Chinese-language interaction, examples, and output conventions. There is no indication that users may choose another language or locale, which can violate language or locale policy when no opt-in is provided.

Static analysis

No suspicious patterns detected.