T09 · Insecure Skill Coding Practices
- Location
scripts/UpdateStock_skill.py:1419- Finding
SQL Injection in MCP-Exposed Stock Query Tools
- Content
View full analysis
= '{start_date}' " if end_date: sql += f"AND trade_date <= '{end_date}' " sql += " ORDER BY trade_date;" with duckdb.connect(DB_path) as conn: df = conn.execute(sql).df() ``` The `get_stock` tool repeats the same unsafe construction: ```python DB_path = fd.get("db_path", "") sql = f"SELECT * FROM stock WHERE symbol='{symbol}' " if start_date: sql += f"AND trade_date >= '{start_date}' " if end_date: sql += f"AND trade_date <= '{end_date}' " sql += " ORDER BY trade_date;" with duckdb.connect(DB_path) as conn: df = conn.execute(sql).df() ``` ### Technical Analysis The MCP-exposed `get_adj_stock` and `get_stock` tools concatenate `symbol`, `start_date`, and `end_date` directly into DuckDB SQL statements. The type annotations and natural-language field descriptions do not enforce the documented six-digit symbol or date formats. A caller can supply quote characters and SQL syntax that alter the intended query. Because the query runs through a DuckDB connection opened with the service's user-level filesystem permissions, exploitation may extend beyond bypassing the stock filters. Depending on the DuckDB configuration and available functionality, an attacker may be able to query unintended tables, modify database content, or access files readable by the service process. The attack surface is particularly relevant because these methods are MCP tools and their parameters may be generated by an AI agent. Prompt injection or an untrusted instruction could the ...[truncated 1294 chars]- Remediation
View remediation
= ?" params.append(start_date) if end_date: sql += " AND trade_date <= ?" params.append(end_date) sql += " ORDER BY trade_date" with duckdb.connect(DB_path) as conn: df = conn.execute(sql, params).df() ``` Apply defense in depth: 1. Require `symbol` to match `^\d{6}$` before executing the query. 2. Parse dates with a strict format such as `%Y-%m-%d`, then pass parsed date values as parameters. 3. Reject unexpected characters rather than attempting to escape SQL manually. 4. Open the database in read-only mode for query-only MCP tools where supported. 5. Use a dedicated database account or sandbox with access only to the intended database directory. 6. Add automated tests containing quotes, comments, union clauses, and stacked-statement payloads to verify that inputs cannot change query structure. ]]>
