T09 · Insecure Skill Coding Practices
- Location
references/install.md:70- Finding
SQL Injection Through Unvalidated Command-Line Arguments
- Content
View full analysis
($NOW_EXPR - ($DAYS * 86400)) AND m.deleted = 0 ORDER BY m.date_sent DESC LIMIT $LIMIT" ;; ``` Date values and the limit are also interpolated directly: ```bash date-range) [ ${#ARGS[@]} -lt 2 ] && { echo "Usage: mail-search date-range YYYY-MM-DD YYYY-MM-DD" >&2; exit 1; } FROM_DATE="${ARGS[0]}"; TO_DATE="${ARGS[1]}" QUERY="SELECT m.ROWID as id, CASE WHEN (m.read = 0) THEN '●' ELSE ' ' END as unread, $DATE_EXPR as date, COALESCE(a.comment, a.address, 'Unknown') as sender, s.subject FROM messages m JOIN subjects s ON m.subject = s.ROWID LEFT JOIN addresses a ON m.sender = a.ROWID WHERE m.date_sent >= (strftime('%s', '$FROM_DATE') - $EPOCH_OFFSET) AND m.date_sent < (strftime('%s', '$TO_DATE', '+1 day') - $EPOCH_OFFSET) AND m.deleted = 0 ORDER BY m.date_sent DESC LIMIT $LIMIT" ;; ``` Message IDs are inserted into SQL without validation: ```bash thread) [ ${#ARGS[@]} -lt 1 ] && { echo "Usage: mail-search thread " >&2; exit 1; } MSG_ID="${ARGS[0]}" QUERY="SELECT m.ROWID as id, CASE WHEN (m.read = 0) TH ...[truncated 4468 chars]- Remediation
View remediation
&2 exit 1 fi } ``` Apply this validation to `LIMIT`, `DAYS`, and every message ID. Enforce sensible upper bounds as well, such as a maximum result limit and maximum recent-day range. 2. **Strictly validate date syntax and calendar validity.** Require the `YYYY-MM-DD` format: ```bash if [[ ! "$FROM_DATE" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] || [[ ! "$TO_DATE" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then echo "Error: dates must use YYYY-MM-DD" >&2 exit 1 fi ``` After checking the shape, parse each value using an appropriate date parser and reject nonexistent dates. 3. **Use parameter binding rather than SQL string interpolation.** Where supported, pass user values through SQLite parameter facilities such as `.parameter` and reference named parameters from the query. Keep SQL syntax static and bind only data values. 4. **Constrain dynamic SQL elements that cannot be bound.** SQLite may not support binding in every structural position in the same way as data values. For `LIMIT`, convert and validate the value as an integer before interpolation. Never place raw input into an SQL structural context. 5. **Reject missing option values and unexpected extra arguments.** Before reading `$2` for options such as `--limit` and `--db`, verify that a value exists. Each command should enforce its exact expected argument count instead of accepting unused trailing arguments. 6. **Reduce the impact of a successful injection.** Keep copied-database mode as the default, clearly warn about the integrity risk of `--no-copy`, and consider removing live-database mode unless it is essential. Open the copied database in read-only/query-only mode where practical, for example by ena ...[truncated 355 chars]
