T09 · Insecure Skill Coding Practices
Error
- Location
- lib/sqlite.js:43
- Finding
- Shell Command Injection in SQLite CLI Invocation<![CDATA[ ## Vulnerability Details **File Location**: `lib/sqlite.js:43-80` **Vulnerability Type**: OS command injection through shell-based process execution **Risk Level**: High ### Vulnerable Code ```js export function sqliteQuery(dbPath, query) { try { const escaped = query .replace(/\n/g, " ") .replace(/\\/g, "\\\\") .replace(/"/g, '\\"') .replace(/\$/g, "\\$"); const raw = execSync( `sqlite3 -json "${dbPath}" "${escaped}"`, { encoding: "utf-8", timeout: 5000 } ).trim(); return raw ? JSON.parse(raw) : []; } catch { return []; } } export function sqliteExec(dbPath, statement) { try { const escaped = statement .replace(/\n/g, " ") .replace(/\\/g, "\\\\") .replace(/"/g, '\\"') .replace(/\$/g, "\\$"); execSync( `sqlite3 "${dbPath}" "${escaped}"`, { encoding: "utf-8", timeout: 5000 } ); return true; } catch { return false; } } ``` Reachable call sites include tool-controlled queries and stored values in `index.js:62-68` and `index.js:92-106`. ### Technical Analysis The plugin passes a dynamically constructed string to `execSync`. When `execSync` receives a command string, Node.js executes it through a shell. The custom escaping only handles newlines, backslashes, double quotes, and dollar signs. It does not escape shell backticks, and `dbPath` is not shell-escaped at all. Backticks embedded in a search query, memory value, or other SQL input remain inside the shell command's double-quoted SQLite argument. POSIX shells process backtick command substitution inside double quotes, causing the enclosed command to execute before `sqlite3` is started. SQL quote escaping performed elsewhere does not prevent this issue because SQL escaping and shell escaping address different parsing layers. An administrator-controlled `dbPath` containing a double quote and shell metacharacters can also terminate the quoted path argument and inject addition ...[truncated 1542 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Eliminate shell interpretation by replacing command-string execution with argument-array execution: ```js import { execFileSync } from "node:child_process"; const raw = execFileSync( "sqlite3", ["-json", dbPath, query], { encoding: "utf-8", timeout: 5000, shell: false } ).trim(); ``` Use the same approach for write operations: ```js execFileSync( "sqlite3", [dbPath, statement], { encoding: "utf-8", timeout: 5000, shell: false } ); ``` 2. Prefer a maintained SQLite API supporting prepared statements and bound parameters. Replace SQL string interpolation with parameterized queries for entity names, keys, values, search terms, IDs, and paths. 3. Normalize `dbPath` with `path.resolve` after expanding the home directory. If the product permits it, restrict database files to a dedicated memory directory. 4. Validate tool argument types and enforce reasonable size limits before query construction. 5. Add regression tests containing backticks, quotes, semicolons, newlines, dollar substitutions, and shell metacharacters. Verify that no side-effect file or command is created during testing. 6. Do not attempt to repair this solely by adding more shell escaping. Avoiding the shell is the reliable control. ]]>
