Back to skill

Security audit

sqlite-reader

Security checks for vulnerabilities and agentic risk

Overview

This skill is a useful SQLite reader, but its query script can also change or damage writable databases despite being presented as read-oriented.

Install only if you are comfortable with a helper that can run arbitrary SQL against databases you point it at. Use it on database copies or read-only files, and do not let untrusted instructions provide SQL queries or output paths.

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
scripts/read_sqlite.py:44
Finding
Unrestricted SQL Execution Against a Writable SQLite Database## Vulnerability Details **File Location**: `scripts/read_sqlite.py`, lines 44–48, 97, and 125 **Vulnerability Type**: Unrestricted state-changing SQL execution in a purported read-only utility **Risk Level**: High ### Vulnerable Code ```python def execute_query(conn, query, limit=None): """Execute a SQL query and return results""" cursor = conn.cursor() try: cursor.execute(query) ``` ```python conn = sqlite3.connect(args.database) ``` ```python elif args.query: result = execute_query(conn, args.query, args.limit) ``` ### Technical Analysis The Skill is documented as a SQLite reader that supports SELECT queries, but the implementation passes the entire user- or agent-supplied `--query` value directly to `cursor.execute()` without enforcing a read-only SQL policy. The database is opened through a normal `sqlite3.connect(args.database)` call rather than a read-only URI. Subject to filesystem permissions, this grants the connection write access. As a result, the query interface can execute state-changing statements such as `INSERT`, `UPDATE`, `DELETE`, `DROP`, and writable `PRAGMA` operations. The `--limit` option only controls how many result rows are fetched; it does not limit or neutralize SQL side effects. Although `cursor.execute()` generally rejects multiple statements in one call, this does not mitigate the issue because a single destructive statement is sufficient to alter or destroy the database. Because the documentation specifically identifies OpenClaw's `main.sqlite` memory database as an intended target, the affected data may include sessions, messages, user details, and transcript paths. ### Attack Path 1. A user or untrusted instruction causes the Skill to inspect a writable SQLite database. 2. The agent passes a state-changing statement through the `--query` argument, for example: ```sql DELETE FROM messages; ``` 3. The script opens the selected database using a writable SQLite connection. 4. `cursor.execu ...[truncated 994 chars]
Remediation
## Remediation Suggestions 1. **Open the database in read-only mode** using a SQLite URI: ```python from pathlib import Path database_uri = Path(args.database).resolve().as_uri() + "?mode=ro" conn = sqlite3.connect(database_uri, uri=True) ``` 2. **Enforce read-only operations with SQLite's authorizer API.** Deny insert, update, delete, schema modification, transaction manipulation, attach/detach, and unsafe PRAGMA actions: ```python def authorize(action, arg1, arg2, database_name, trigger_name): denied = { sqlite3.SQLITE_INSERT, sqlite3.SQLITE_UPDATE, sqlite3.SQLITE_DELETE, sqlite3.SQLITE_CREATE_TABLE, sqlite3.SQLITE_DROP_TABLE, sqlite3.SQLITE_ALTER_TABLE, sqlite3.SQLITE_ATTACH, sqlite3.SQLITE_DETACH, } return sqlite3.SQLITE_DENY if action in denied else sqlite3.SQLITE_OK conn.set_authorizer(authorize) ``` 3. **Permit only read-only statements.** Do not rely solely on a textual prefix check, because comments, PRAGMAs, and complex SQL syntax can bypass simplistic validation. Use the read-only connection and authorizer as the primary controls. 4. **Reject queries that return no result-set metadata** and handle `cursor.description is None` safely. 5. **Add explicit confirmation and a separate administrative mode** if write functionality is ever intentionally introduced. It should not share the reader's default execution path. 6. **Add security tests** confirming that `INSERT`, `UPDATE`, `DELETE`, `DROP`, `ALTER`, `ATTACH`, `DETACH`, and writable PRAGMA statements are denied while legitimate `SELECT` and schema-inspection operations remain available. 7. **Update the documentation** to accurately state and guarantee that arbitrary queries are constrained to read-only behavior.
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 (3)

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The script presents itself as a SQLite reader, but `execute_query` passes arbitrary user-supplied SQL directly to `cursor.execute(query)` without restricting statements to read-only operations. In this skill context, that makes the capability more dangerous because a user or calling agent expecting safe inspection of `.sqlite` files could instead modify or delete data, create objects, or trigger side effects against the database file.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill advertises only SQLite read/query functionality, but its content includes creating a Python script and exporting data to CSV/JSON, which implies file-write capability without any declared tool scope or permission boundary. This mismatch can enable unintended filesystem modification or data exfiltration paths, especially if an agent auto-generates and runs helper scripts based on the skill instructions.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The manifest focuses on reading/querying SQLite files and inspecting data, but this function writes query results out to an arbitrary filesystem path. While related to extraction, it extends behavior from database reading into local file creation, which is not stated in the manifest description.

Static analysis

No suspicious patterns detected.