# Vulnerability Knowledge Base - Agent Quick Reference

Condensed detection heuristics from CWE Top 25. Read this file during `/plan-swarm-review` code mode
to get focused checklists per vulnerability class.

Full entries with code examples, root cause analysis, and fixing patterns:
`knowledge-vault/docs/security/cwe/` (10 entries, Vul-RAG format)

---

## CWE-79: Cross-Site Scripting (XSS) [Rank 1]

**Trace:** user input -> DOM insertion without escaping

**Triggers:**
- `innerHTML`, `outerHTML`, `insertAdjacentHTML` with non-constant RHS
- `document.write(`, `eval(`, `new Function(`, `setTimeout(string`
- React: `dangerouslySetInnerHTML={{ __html: expr }}` where expr is not literal
- Vue: `v-html="expr"` without sanitized computed property
- Angular: `bypassSecurityTrustHtml(`, `bypassSecurityTrustScript(`
- jQuery: `.html(expr)`, `.append(expr)` where expr is user-derived
- `window.addEventListener("message", ...)` without `event.origin` check
- `location.hash`, `location.search`, `document.referrer` -> DOM sink

**NOT vuln if:** framework auto-escapes (React JSX, Angular templates without bypass), DOMPurify applied before insertion, CSP with no `unsafe-inline`

---

## CWE-787: Out-of-bounds Write [Rank 2]

**Trace:** external input -> buffer write without bounds check

**Triggers:**
- `memcpy(dst, src, len)` where `len` from external input without `len <= sizeof(dst)`
- `strcpy`, `strcat`, `gets`, `sprintf` (without `n` variants) - automatic finding
- `arr[i]` write where `i` from network/file/IPC source
- `malloc(a * b)` where either operand is external - overflow possible
- `for (i = 0; i <= len; i++)` - off-by-one (`<=` should be `<`)
- Pointer arithmetic `ptr + offset` without bounds check

**Taint:** source = `read()`, `recv()`, `fread()`, `getenv()`, `argv[]`; sink = `memcpy dst`, `strcpy dst`, array subscript write

---

## CWE-89: SQL Injection [Rank 3]

**Trace:** HTTP input -> query construction via string concatenation

**Triggers:**
- `f"SELECT ... {user_var}"`, `"SELECT ... " + user_var`
- ORM escape hatches: Django `raw()`, `extra()`, `RawSQL()`; SQLAlchemy `text()`, `literal_column()`
- Dynamic table/column names: `f"SELECT * FROM {table}"` (parameterization doesn't cover identifiers)
- `LIKE` with unescaped `%` and `_`: `WHERE name LIKE '%{input}%'`
- PostgreSQL JSONB: `jsonb_path_query(data, user_input)` - JSON path injection
- GraphQL resolvers building raw queries from field arguments
- Second-order: stored unsanitized, later used in query

**NOT vuln if:** parameterized queries with `%s`/`?` placeholders, ORM default `.filter()` methods, identifier validated against allowlist

---

## CWE-125: Out-of-bounds Read [Rank 6]

**Trace:** claimed_length from data stream -> read beyond actual buffer

**Triggers:**
- `memcpy(dst, src, n)` where `n` from same data as `src` (Heartbleed pattern)
- `strlen(buf)` where `buf` not guaranteed null-terminated (packet/file format fields)
- `printf(user_string)` without format arg - format string vuln
- `arr[i]` read where `i` is `int` from external, only upper-bound checked (negative values)
- `strncpy(dst, src, n)` then use `dst` as C-string - no null termination guarantee

**Key difference from CWE-787:** reads don't corrupt memory but leak secrets (keys, passwords, adjacent allocations)

---

## CWE-416: Use After Free [Rank 8]

**Trace:** `free(ptr)` -> later use of `ptr` or alias

**Triggers:**
- `free(ptr)` followed by read/write/call via `ptr` without intervening `ptr = NULL`
- `free(ptr)` inside function that returns `ptr` or stores elsewhere - multiple ownership
- Destructor where pointer in multiple structures: `A.ptr = p; B.ptr = p; delete p;`
- Event system: `subscribe(lambda capturing raw pointer)` without unsubscribe in destructor
- Container modified during iteration: range-for with `erase`/`insert`/`push_back`
- Multithreaded: `free()` in one thread, use in another, no synchronization

**Tools:** Clang `scan-build`, Cppcheck `--enable=warning`, Coverity USE_AFTER_FREE, CodeQL `cpp/use-after-free`, ASan/MSan at runtime

---

## CWE-434: Unrestricted File Upload [Rank 10]

**Trace:** user file upload -> server storage/execution

**Triggers:**
- Find handlers: `multipart/form-data`, `request.FILES`, `multer`, `IFormFile`
- Extension bypass: `.php5`, `.phtml`, `.php%00.jpg` (null byte), `.asp;.jpg`
- MIME validation via `Content-Type` header only (attacker controls header)
- Upload destination inside webroot with execute permissions
- Filename from user input without `basename()` - path traversal
- No image reprocessing on image uploads - polyglot/metadata payload risk
- Served with guessed `Content-Type` from extension

---

## CWE-502: Deserialization [Rank 16]

**Trace:** user-controlled bytes -> deserialization call

**Triggers:**
- Java: `ObjectInputStream`, `readObject`, `readUnshared` on non-constant stream
- Python: `pickle.loads`, `pickle.load` on user data; `yaml.load(` without `Loader=yaml.SafeLoader`
- PHP: `unserialize(` without `allowed_classes`
- .NET: `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` (all deprecated)
- Ruby: `Marshal.load` on non-hardcoded input
- Node: `eval(` in node-serialize path

**Gadget chain indicators:** commons-collections, spring-beans, ysoserial deps in classpath (Java); `__reduce__` in class defs (Python)

---

## CWE-918: SSRF [Rank 19]

**Trace:** user-controlled URL -> server HTTP client call

**Triggers:**
- `requests.get(url)`, `urllib.request.urlopen(url)`, `httpx.get(url)` where url from request params
- `axios.get(req.body.url)`, `fetch(req.query.callbackUrl)`
- URL by string concatenation: `"http://" + req.params.host + "/api/"`
- `allow_redirects=True` (default in requests) with user-supplied URL
- Cloud metadata: `169.254.169.254` reachable from container (IMDSv1 not disabled)
- Docker API on `0.0.0.0:2375` (no TLS)

**NOT vuln if:** URL validated against strict allowlist (not denylist), post-resolution IP check against RFC 1918 ranges, redirects disabled

---

## CWE-190: Integer Overflow [Rank 23]

**Trace:** user-controlled arithmetic -> allocation size / array index / security check

**Triggers:**
- `malloc(a * b)` where `a` or `b` from user input without overflow check
- `new T[user_value]` or `make([]T, user_value)` without bounds
- Narrowing cast: `(int)userLong`, `(uint8_t)userInt`
- Mixed signed/unsigned comparison: `if (signed_var < unsigned_constant)`
- Java: `(int)(userLong * constant)` without `Math.multiplyExact`

**Consequences:** undersized allocation -> CWE-787, index OOB, security check bypass, incorrect financial calculations

---

## CWE-400: Resource Consumption / DoS [Rank 24]

**Trace:** user-controlled input -> unbounded resource allocation

**Triggers:**
- ReDoS: regex with nested quantifiers `(X+)+`, `(X*Y*)+` on user string
- Decompression bombs: `zipfile.read()`, `gzip.decompress()` without size check
- XML entity expansion: parsing without `resolve_entities=False`
- Unbounded collections: `list.append()` in request handler without size cap
- Recursive function where depth = user JSON nesting level
- GraphQL without depth/complexity limits
- Missing `MAX_CONTENT_LENGTH` (Flask), `client_max_body_size` (Nginx)
- Hash collision attacks on user-controlled keys (Python <3.3 dicts)

**NOT vuln if:** timeouts on regex, decompression size limits, XML entity resolution disabled, collection size caps, rate limiting
