T09 · Insecure Skill Coding Practices
- Location
scripts/jmail-duckdb.sh:169- Finding
Second-Order SQL Injection Through an Untrusted Dataset Value
- Content
View full analysis
/dev/null | head -1) if [[ -n "$RESOLVED_SLUG" ]]; then FROM_FILTER="AND m.conversation_slug = '${RESOLVED_SLUG}'" echo " (filtered to: ${RESOLVED_SLUG})" else echo " ⚠️ No conversation found for '${FROM_NAME}', searching all" FROM_FILTER="" fi run_query " SELECT c.name as conversation, m.sender, m.text, m.time FROM read_parquet('${MSGS}') m JOIN read_parquet('${CONVOS}') c ON m.conversation_slug = c.slug WHERE m.text ILIKE '%${QUERY}%' ${FROM_FILTER} ORDER BY m.timestamp LIMIT 50; " ``` ### Technical Analysis `FROM_NAME` is passed through the script's sanitizer before use, but `RESOLVED_SLUG` is obtained from `imessage_conversations.parquet`, a remotely downloaded dataset. The returned slug is then interpolated directly into a second SQL statement without validation, escaping, or parameter binding. This is a second-order SQL injection: the dangerous value does not come directly from the command-line argument. Instead, attacker-controlled SQL syntax can be stored in the dataset, selected by the first query, and executed when the result is incorporated into the subsequent query. For example, a malicious slug containing a quote followed by additional DuckDB SQL could terminate the `conversation_slug` string literal and alter the second command. The use of `head -1` limits the result to one line but does not make the value safe for SQL interpolation. ### Attack Path 1. An attacker compromises the remote Parquet source, controls an upstream dataset-generation process, or causes the local cache to contain a malicious `imessage_conversations.parquet`. 2. The attacker inserts a co ...[truncated 1523 chars]- Remediation
View remediation
&2 exit 1 fi ``` 3. Prefer DuckDB parameter binding or a safely generated SQL literal instead of direct string interpolation. 4. Avoid constructing an SQL fragment in `FROM_FILTER`. Build separate fixed query forms for filtered and unfiltered searches. 5. Reject multiline, malformed, or ambiguous CSV output before using it in another command. 6. Where supported, restrict DuckDB external access and disable unneeded extension installation or loading. 7. Verify downloaded datasets using trusted checksums or signatures before querying them. 8. Update the security documentation so that it accurately reflects the trust boundary around remotely sourced Parquet content. ]]>
