T09 · Insecure Skill Coding Practices
- Location
scripts/query.mjs:34- Finding
Arbitrary Local File Disclosure Through Unrestricted --sql-file Input
- Content
View full analysis
--sql \"SELECT ...\" | --sql-file "); process.exit(1); } const result = await callTool("query", { dataset_id: datasetId, sql: querySql }); ``` The corresponding outbound request is implemented in `scripts/client.mjs:76-98`: ```js export async function mcpCall(method, params = {}) { const apiKey = requireEnv("POND3R_API_KEY"); const headers = { "Content-Type": "application/json", Accept: "application/json, text/event-stream", Authorization: `Bearer ${apiKey}`, }; if (_sessionId) { headers["Mcp-Session-Id"] = _sessionId; } const body = { jsonrpc: "2.0", id: Date.now(), method, params, }; const res = await fetch(MCP_URL, { method: "POST", headers, body: JSON.stringify(body), }); ``` ### Technical Analysis The `--sql-file` option accepts an arbitrary filesystem path and passes it directly to `readFileSync`. The implementation does not constrain the path to a designated query directory, reject symbolic links, enforce a file extension or size limit, or verify that the resulting content is a read-only SQL statement. After the file is read, its complete contents are assigned to `querySql`, embedded in the `tools/call` request as the `sql` argument, and transmitted over HTTPS to the fixed Pond3r MCP endpoint. Any remote rejection or server-side SQL validation occurs only after the request body—and therefore the selected file contents—has already been transmitted. The documented “SELECT only” restriction ...[truncated 1869 chars]- Remediation
View remediation
