Code security review criteria
Review the worker's code draft against security + correctness checks. Strict: when in doubt, REVISE rather than APPROVE.
Critical checks (any failure = REVISE)
No SQL injection vectors:
- String concatenation into queries: REVISE
- User input passed to
sql.unsafe()without param array: REVISE - Drizzle / parameterised queries: OK
No secret leakage:
- Hardcoded API keys, tokens, passwords in the draft: REVISE
- Logging full request bodies that might contain secrets: REVISE
- Returning provider error responses verbatim (often contain API keys in URLs): REVISE
Auth checks present:
- Routes that read/write user data must check
c.get('userId')or equivalent - Routes that mutate must check ownership (the row's userId matches the caller's userId)
- Admin-only routes must check role
- Routes that read/write user data must check
No prototype pollution:
Object.assign(target, untrustedInput)where target is shared state: REVISE- Deep merges of user input into config: REVISE
No SSRF:
fetch(userProvidedUrl)without scheme/host validation: REVISE- URL parsing with allowlist: OK
Quality checks (single failure = REVISE; multiple = REJECT)
Error handling at boundaries:
- External fetches wrapped in try/catch
- Returns structured errors (not raw provider responses)
No silent failures:
- Empty catch blocks: REVISE
- Errors logged then swallowed without explanation: REVISE
Project conventions:
- Uses Drizzle, not raw D1 (where available)
- Uses Hono context, not Express patterns
- Imports from
@/server/...not relative../../../
When to APPROVE
- All 5 critical checks pass
- All quality checks pass or have one minor REVISE-worthy item that was already addressed
When to REVISE
- 1-2 specific issues from the lists above. Be concrete: "line 12
concatenates
userIdinto the query string — switch toeq(table.userId, userId)"
When to REJECT
- Multiple critical security issues
- The code answers a different question (wrong API, wrong table, wrong file scope)
- Architectural mismatch — uses patterns the project explicitly avoids per its CLAUDE.md
Verdict format
VERDICT: APPROVE — auth check + parameterised query + error handling all present
VERDICT: REVISE — line 18 logs the full request body which contains the API key in headers
VERDICT: REJECT — uses raw SQL string concat for the user-supplied filter; multiple injection vectors