injection · git:20260914.1ef9fbc · 2026-09-14 · sha256 be062b7ad0d1e124

injection git:20260914.1ef9fbcA

Immutable. This exact content never changes and is served at /api/v1/blob/be062b7ad0d1e124.

---
name: injection
description: Classify injection evidence — command injection (system/popen) and SQL injection (sprintf+sqlite3_exec). Maps to CWE-78, CWE-89.
license: MIT
compatibility: opencode,claude code,DSH
metadata:
  cwe: CWE-78
  severity: CRITICAL
  domain: security
---

## Injection Analysis (CWE-78, CWE-89)

### Evidence Patterns

#### Command Injection (CWE-78)
- **INJECTION event** with category `command_injection`
- Unsafe function: `system()`, `popen()` with user-controlled input
- No input sanitization or use of safe alternative (`execve`)

#### SQL Injection (CWE-89)
- **INJECTION event** with category `sql_injection`
- String concatenation/sprintf to build SQL query
- No parameterized query (`sqlite3_prepare_v2` + `sqlite3_bind_text`)

### Safe Alternatives (P0 Exclusion)

| Unsafe | Safe Alternative | Why Safe |
|--------|-----------------|----------|
| `system(cmd)` | `execve(path, argv, env)` | No shell interpretation |
| `popen(cmd, ...)` | `fork + execv` | No shell interpretation |
| `sprintf(query, "...%s...", input)` | `sqlite3_prepare_v2 + bind` | Parameterized query |

### Safe Wrappers (P1 Exemption)

| Wrapper | Guarantee |
|---------|-----------|
| `SafeQuery_prepare(db, sql)` | Uses prepared statement |
| `SafeQuery_bind_text(q, idx, val)` | Binds parameter safely |
| `SafeQuery_exec(q)` | Executes prepared statement |

### Classification Rules

| Condition | Classification |
|-----------|---------------|
| `system()` with user input, no sanitization | **confirmed** |
| `system()` with user input + blacklist sanitization | **confirmed** (a blacklist filters some characters but is always bypassable) |
| `system()` with user input + whitelist/validation | **false-positive** |
| `execve()` with fixed path + args | **false-positive** |
| `sprintf` building SQL with user input | **confirmed** |
| `sqlite3_prepare_v2 + bind_text` | **false-positive** |
| `sqlite3_exec` with concatenated query | **confirmed** |

### Common Edge Cases (P3)
- **Partial blacklist**: `is_safe_input()` filtering `;` but not `&&`, `||`, `$()` → **confirmed** (incomplete sanitization is still injectable)
- **TOCTOU**: Check then use with race window → **dismissed**
- **Format string**: `printf(user_input)` without format → **confirmed** (CWE-134)

### Fix Suggestions
- Command execution: Use `execve` with argument array, never `system()`
- SQL: Use prepared statements with parameter binding
- Input validation: Use whitelist, not blacklist
- Format strings: Use `printf("%s", user_input)`, never `printf(user_input)`

### Severity Matrix

`status` and `severity` are independent: `status` = evidence verdict
(confirmed/dismissed), `severity` = impact (low/medium/high/critical).
`metadata.severity` is the type default, not a ceiling. The verdict is binary (confirmed/dismissed); dismissed → `low`.

| Shape | Severity |
|-------|----------|
| Command injection: tainted input reaches `system`/`popen` | CRITICAL |
| SQL injection: tainted input reaches a concatenated/sprintf query | CRITICAL |
| TOCTOU / unproven taint reaching the sink | HIGH (dismissed) |