Security Review Skill
Perform a security-focused code review that identifies real, exploitable vulnerabilities and provides proof-of-concept demonstrations. Produces a high-signal report with two distinct sections: confirmed vulnerabilities with PoCs, and separate security hardening recommendations.
Critical Principles
Only report real vulnerabilities. Every vulnerability in the report must be grounded in how the code actually works, not how it theoretically could be misused. Trace data flow from attacker-controlled input to the dangerous operation. If the path is blocked by validation, type constraints, or other controls, it is not a vulnerability.
Investigate before reporting. If you encounter a pattern that looks suspicious but you are not certain it is exploitable, DO NOT include it in the report as a vulnerability. Instead, investigate it:
- Use the Task tool with
subagent_type: "general-purpose" to spawn an investigation agent. Instruct it to trace the data flow, read all relevant code paths, and determine whether the issue is actually exploitable.
- Only include the finding if the investigation confirms it is a real problem.
Every vulnerability needs a proof of concept. If you cannot write a PoC that demonstrates the vulnerability, it does not belong in the Vulnerabilities section. If it is a genuine concern but you cannot prove exploitability, put it in the Hardening section instead.
Separate vulnerabilities from hardening. Vulnerabilities are confirmed exploitable issues rated High, Medium, or Low. Hardening recommendations are defense-in-depth improvements that do not address a specific confirmed vulnerability.
Workflow
1. Determine Scope
Identify what to review:
Detect the primary language(s) in scope to determine which language-specific checks apply.
Determine what kind of software is being reviewed (CLI tool, library, server, etc.) as this affects how PoCs are written.
2. Enumerate Attack Surface
Before reading code, identify the attack surface by searching for:
| Surface |
Search Patterns |
| Network listeners |
net.Listen, http.ListenAndServe, TcpListener::bind, hyper::Server |
| HTTP handlers |
HandleFunc, Handler, #[get, #[post, axum::Router, actix_web |
| User input parsing |
json.Unmarshal, serde::Deserialize, ParseForm, FromStr |
| File system access |
os.Open, os.Create, std::fs::, ioutil.ReadFile |
| Database queries |
db.Query, db.Exec, sqlx::query, diesel:: |
| External commands |
exec.Command, std::process::Command, os/exec |
| Cryptographic operations |
crypto/, ring::, sha, hmac, aes, rand |
| Authentication/authorization |
token, jwt, session, auth, permission, rbac |
| Environment/config |
os.Getenv, std::env::var, viper, config |
3. Review Code
Read each file in scope. For every file, check against:
- General security checklist (Section: General Checks)
- Language-specific checklist (Section: Go Checks or Rust Checks)
- Context-specific concerns based on the attack surface found in Step 2
For every potential finding, ask yourself:
- Is this reachable from attacker-controlled input? Trace the data flow backwards from the dangerous operation to an input source. Read the actual code at each step. If you cannot trace a path from untrusted input to the dangerous operation, it is not a vulnerability.
- Are there existing controls that mitigate this? Read the surrounding code, middleware, validation layers, and type constraints. If the issue is already mitigated, it is not a vulnerability.
- Can I demonstrate this with a concrete PoC? If not, it belongs in Hardening at most.
4. Investigate Uncertain Findings
For any finding where you are not confident it is exploitable:
Spawn an investigation agent using the Task tool:
Task tool with subagent_type: "general-purpose"
Prompt: "Investigate whether [description of the suspicious pattern] in [file:line]
is actually exploitable. Trace the data flow from any attacker-controlled input to
this operation. Read all relevant validation, middleware, type constraints, and
calling code. Determine:
1. Can an attacker reach this code path with controlled input?
2. Are there existing mitigations that prevent exploitation?
3. If exploitable, what is the concrete attack scenario?
Report back with your conclusion: CONFIRMED, NOT EXPLOITABLE, or NEEDS MORE CONTEXT."
If the agent reports NOT EXPLOITABLE, drop the finding entirely. Do not include it in the report. If CONFIRMED, proceed to write a PoC. If NEEDS MORE CONTEXT, make a judgment call: either investigate further or move it to Hardening with a note about what is uncertain.
5. Write Proof of Concept for Each Vulnerability
Every vulnerability must have a minimal PoC that demonstrates exploitability. The format depends on the type of software:
For a CLI tool:
# PoC: [vulnerability name]
# Expected: [what should happen safely]
# Actual: [what happens due to the vulnerability]
command --flag "$(malicious_payload)"
For a library:
// PoC: [vulnerability name]
package main
import "vulnerable/package"
func main() {
// Minimal code that triggers the vulnerability
result := package.VulnerableFunction(maliciousInput)
// Demonstrate the impact
}
// PoC: [vulnerability name]
use vulnerable_crate::vulnerable_function;
fn main() {
// Minimal code that triggers the vulnerability
let result = vulnerable_function(malicious_input);
// Demonstrate the impact
}
For a server:
# PoC: [vulnerability name]
# Step 1: [setup if needed]
curl -X POST http://localhost:8080/endpoint \
-H "Content-Type: application/json" \
-d '{"malicious": "payload"}'
# Expected response: [what safe behavior looks like]
# Actual response: [what the vulnerability produces]
The PoC must be minimal — only the code necessary to trigger the issue and nothing else.
6. Classify Findings
All confirmed vulnerabilities are rated on this scale:
| Severity |
Criteria |
| High |
Exploitable with no or minimal preconditions. Leads to RCE, authentication bypass, privilege escalation, data breach, or significant data exposure. |
| Medium |
Exploitable but requires specific conditions (authenticated attacker, particular configuration, race condition timing). Impact is meaningful but bounded. |
| Low |
Exploitable but impact is limited (minor information disclosure, DoS requiring sustained effort, issues only exploitable in non-default configurations). |
Hardening recommendations are not rated on this scale. They are listed separately without severity ratings.
7. Write Report
Write the report to SECURITY_REVIEW.md in the current working directory with this structure:
# Security Review
**Scope:** {files or directories reviewed}
**Date:** {date}
**Languages:** {detected languages}
**Software type:** {CLI tool / library / server / etc.}
## Summary
{1-3 sentences. State the number of confirmed vulnerabilities found and their severity breakdown. If none found, say so clearly.}
---
## Vulnerabilities
{If no vulnerabilities were found, state: "No confirmed vulnerabilities were identified."}
### HIGH-001: {Finding Title}
**File:** `path/to/file.go:42`
**Category:** {e.g., Injection, Authentication, Cryptography}
**Description:**
{What the vulnerability is. Be specific about the data flow: what attacker-controlled input reaches what dangerous operation, and why existing controls do not prevent it.}
**Vulnerable Code:**
{The specific code snippet containing the vulnerability}
**Proof of Concept:**
{Minimal PoC demonstrating the vulnerability — commands, code, or HTTP requests}
**Recommendation:**
{How to fix it, with a corrected code example}
---
### MED-001: {Finding Title}
{same structure}
---
### LOW-001: {Finding Title}
{same structure}
---
## Security Hardening
{Defense-in-depth recommendations that do not address a specific confirmed vulnerability. These are improvements to security posture.}
### {Recommendation Title}
**File:** `path/to/file.go:42` (if applicable)
**Description:**
{What could be improved and why it strengthens security posture, even though it does not address a specific confirmed vulnerability.}
**Suggestion:**
{Concrete code or configuration change}
8. Present to User
After writing the report, summarize the confirmed vulnerabilities inline. Do not summarize hardening items — they are secondary. Ask if the user wants to discuss any specific finding in detail.
General Checks
Apply these checks regardless of language. Remember: only flag items where you can trace attacker-controlled input to a dangerous operation without existing mitigation.
Input Validation
- Untrusted input used directly in SQL queries, commands, file paths, or URLs
- Missing or insufficient length/size limits on inputs
- Improper handling of Unicode, null bytes, or encoding edge cases
- Path traversal via
../ or absolute paths in user-supplied filenames
- SSRF via user-controlled URLs used in outbound requests
Authentication and Authorization
- Missing authentication on sensitive endpoints
- Authorization checks that can be bypassed (IDOR, missing ownership checks)
- Hard-coded credentials, API keys, or tokens
- Timing-safe comparison not used for secrets (
== instead of constant-time compare)
- Session tokens with insufficient entropy or predictable generation
Cryptography
- Use of broken algorithms (MD5, SHA1 for security purposes, DES, RC4)
- Hard-coded keys, IVs, or nonces
- Nonce reuse in AEAD ciphers
- Use of ECB mode
- Custom cryptographic implementations instead of vetted libraries
- Insufficient key lengths (RSA < 2048, symmetric < 128-bit)
- Missing integrity protection (encryption without authentication)
Error Handling
- Stack traces, internal paths, or debug info exposed to users
- Errors that reveal whether a user/resource exists (enumeration)
- Catch-all error handlers that swallow security-relevant failures
- Panics or crashes reachable from untrusted input
Secrets Management
- Secrets logged to stdout/stderr or log files
- Secrets in source code, config files committed to VCS, or environment variable defaults
- Secrets not zeroed from memory after use
.env files, private keys, or credential files in the repository
Concurrency
- Race conditions in authentication or authorization checks (TOCTOU)
- Shared mutable state without synchronization
- Double-spend or duplicate-action vulnerabilities from concurrent requests
Dependency and Supply Chain
- Dependencies with known CVEs (check go.sum, Cargo.lock)
- Pinned to mutable refs (branches,
latest) instead of exact versions or hashes
- Vendored code that has been modified from upstream
Go Checks
Apply these when reviewing Go code.
Injection
fmt.Sprintf used to build SQL queries instead of parameterized queries
os/exec.Command with user-controlled arguments not validated against an allowlist
text/template used where html/template is needed (XSS)
- String concatenation in
database/sql query construction
Error Handling
- Errors discarded with
_ = on security-critical operations (file permissions, crypto, auth)
defer closing a resource but ignoring the close error (can mask write failures)
recover() catching panics broadly, masking security failures
- Missing error checks on
io.Copy, http.Response.Body.Close
HTTP and Networking
- Missing TLS configuration or insecure
TLSClientConfig (InsecureSkipVerify: true)
http.DefaultClient used without timeouts (enables slowloris DoS)
- Missing
http.MaxBytesReader on request bodies (memory exhaustion)
- CORS headers set to
* or reflecting origin without validation
- Missing CSRF protection on state-changing endpoints
http.Redirect with user-controlled URL (open redirect)
Concurrency
- Race conditions on maps (concurrent read/write without
sync.Map or mutex)
- Goroutine leaks from missing context cancellation or unbounded channel sends
sync.WaitGroup misuse (Add/Done mismatch)
- Shared slice/map modified across goroutines without synchronization
Unsafe Operations
- Use of
unsafe package for pointer arithmetic or type punning
reflect used to bypass unexported field protections
cgo calls with unchecked buffer sizes or missing null termination
//go:linkname used to access internal runtime functions
Cryptographic Pitfalls
math/rand used where crypto/rand is required (token generation, nonces)
crypto/subtle.ConstantTimeCompare not used for secret comparison
- Custom
hash.Hash usage without proper reset between uses
crypto/tls config missing MinVersion: tls.VersionTLS12
Integer and Memory
- Integer overflow in
make([]byte, userControlledSize) causing allocation issues
- Slice bounds not checked before indexing with external values
strconv.Atoi result used without range validation
File and OS
os.MkdirAll with overly permissive mode (0777)
os.OpenFile without validating symlink targets (symlink following)
- Temporary files created in shared directories without
os.CreateTemp
- Missing
filepath.Clean on user-supplied paths
Rust Checks
Apply these when reviewing Rust code.
Unsafe Code
- Every
unsafe block: verify the safety invariants documented and upheld
- Raw pointer dereferencing without null/alignment checks
std::mem::transmute used for type punning (verify layout compatibility)
unsafe impl Send/Sync on types containing raw pointers or non-thread-safe internals
from_raw_parts / from_raw_parts_mut with unchecked length or alignment
ManuallyDrop or std::mem::forget causing resource leaks (file handles, locks)
- FFI boundaries: missing null checks, buffer size validation, lifetime guarantees
Error Handling
.unwrap() or .expect() on Result/Option reachable from untrusted input
panic! in library code reachable from external callers
? propagation that discards context needed for security decisions
catch_unwind used as a substitute for proper error handling
Memory Safety (even in safe Rust)
- Logic errors in index arithmetic leading to out-of-bounds via
.get_unchecked()
Vec::set_len() on uninitialized memory
- Stack overflow via unbounded recursion on attacker-controlled input
- Large allocations from user-controlled sizes (
Vec::with_capacity(user_input))
Serialization and Parsing
serde deserialization of untrusted input without size limits or depth limits
#[serde(deny_unknown_fields)] missing on security-critical config structs
- Custom
Deserialize implementations with unchecked invariants
- Deserializing into
enum variants that trigger different privilege levels
Web and Network (axum, actix-web, hyper, tokio)
- Missing request body size limits (
tower_http::limit::RequestBodyLimitLayer)
- Timeout not configured on server or client connections
- Missing TLS certificate validation on HTTP clients (
danger_accept_invalid_certs)
- Shared mutable state in handlers without
Arc<Mutex<_>> or Arc<RwLock<_>>
- Missing authentication middleware on protected routes
tower layers ordered incorrectly (auth after handler, rate limit after auth)
Concurrency
Mutex poisoning not handled (lock().unwrap() on potentially poisoned mutex)
Arc reference cycles causing memory leaks
- Deadlock potential from inconsistent lock ordering
tokio::spawn without JoinHandle tracking (silent task failures)
- Blocking operations in async context (
std::fs in tokio runtime, std::thread::sleep)
Cryptographic Pitfalls
rand::thread_rng() used where rand::rngs::OsRng is needed for cryptographic randomness
ring or rustcrypto primitives used without authenticated encryption
- Custom serialization of cryptographic keys without constant-time comparison
- Timing side-channels in comparison operations (
== on secrets)
Supply Chain and Build
build.rs executing arbitrary code at compile time
proc_macro dependencies with network access or file system writes
[patch] or [replace] in Cargo.toml overriding dependencies
- Feature flags that silently disable security features (
#[cfg(not(feature = "tls"))])
Integer Safety
- Arithmetic operations that can overflow/underflow (use
checked_*, saturating_*, or wrapping_*)
as casts that truncate or sign-extend (u64 as u32, i32 as u32)
usize used for serialized data sizes across architectures (32 vs 64-bit mismatch)
1---2name: security-review-103description: Review code for security vulnerabilities. Use when asked to "security review", "audit code", "find vulnerabilities", "check for security issues", "pentest review", or "security audit" a codebase or set of files.4---5
6# Security Review Skill
7
8Perform a security-focused code review that identifies real, exploitable vulnerabilities and provides proof-of-concept demonstrations. Produces a high-signal report with two distinct sections: confirmed vulnerabilities with PoCs, and separate security hardening recommendations.
9
10## Critical Principles
11
121. **Only report real vulnerabilities.** Every vulnerability in the report must be grounded in how the code actually works, not how it theoretically could be misused. Trace data flow from attacker-controlled input to the dangerous operation. If the path is blocked by validation, type constraints, or other controls, it is not a vulnerability.
13
142. **Investigate before reporting.** If you encounter a pattern that looks suspicious but you are not certain it is exploitable, DO NOT include it in the report as a vulnerability. Instead, investigate it:
15 - Use the Task tool with `subagent_type: "general-purpose"` to spawn an investigation agent. Instruct it to trace the data flow, read all relevant code paths, and determine whether the issue is actually exploitable.
16 - Only include the finding if the investigation confirms it is a real problem.
17
183. **Every vulnerability needs a proof of concept.** If you cannot write a PoC that demonstrates the vulnerability, it does not belong in the Vulnerabilities section. If it is a genuine concern but you cannot prove exploitability, put it in the Hardening section instead.
19
204. **Separate vulnerabilities from hardening.** Vulnerabilities are confirmed exploitable issues rated High, Medium, or Low. Hardening recommendations are defense-in-depth improvements that do not address a specific confirmed vulnerability.
21
22## Workflow
23
24### 1. Determine Scope
25
26Identify what to review:
27
28- If the user specifies files or directories, use those.
29- If the user provides a PR number or branch, get the diff:
30 ```bash
31 git diff main...HEAD --name-only
32 ```
33- If no scope is given, ask the user what to review.
34
35Detect the primary language(s) in scope to determine which language-specific checks apply.
36
37Determine what kind of software is being reviewed (CLI tool, library, server, etc.) as this affects how PoCs are written.
38
39### 2. Enumerate Attack Surface
40
41Before reading code, identify the attack surface by searching for:
42
43| Surface | Search Patterns |
44|---------|----------------|
45| Network listeners | `net.Listen`, `http.ListenAndServe`, `TcpListener::bind`, `hyper::Server` |
46| HTTP handlers | `HandleFunc`, `Handler`, `#[get`, `#[post`, `axum::Router`, `actix_web` |
47| User input parsing | `json.Unmarshal`, `serde::Deserialize`, `ParseForm`, `FromStr` |
48| File system access | `os.Open`, `os.Create`, `std::fs::`, `ioutil.ReadFile` |
49| Database queries | `db.Query`, `db.Exec`, `sqlx::query`, `diesel::` |
50| External commands | `exec.Command`, `std::process::Command`, `os/exec` |
51| Cryptographic operations | `crypto/`, `ring::`, `sha`, `hmac`, `aes`, `rand` |
52| Authentication/authorization | `token`, `jwt`, `session`, `auth`, `permission`, `rbac` |
53| Environment/config | `os.Getenv`, `std::env::var`, `viper`, `config` |
54
55### 3. Review Code
56
57Read each file in scope. For every file, check against:
58
591. **General security checklist** (Section: General Checks)
602. **Language-specific checklist** (Section: Go Checks or Rust Checks)
613. **Context-specific concerns** based on the attack surface found in Step 2
62
63For every potential finding, ask yourself:
64
65- **Is this reachable from attacker-controlled input?** Trace the data flow backwards from the dangerous operation to an input source. Read the actual code at each step. If you cannot trace a path from untrusted input to the dangerous operation, it is not a vulnerability.
66- **Are there existing controls that mitigate this?** Read the surrounding code, middleware, validation layers, and type constraints. If the issue is already mitigated, it is not a vulnerability.
67- **Can I demonstrate this with a concrete PoC?** If not, it belongs in Hardening at most.
68
69### 4. Investigate Uncertain Findings
70
71For any finding where you are not confident it is exploitable:
72
73Spawn an investigation agent using the Task tool:
74
75```
76Task tool with subagent_type: "general-purpose"
77
78Prompt: "Investigate whether [description of the suspicious pattern] in [file:line]
79is actually exploitable. Trace the data flow from any attacker-controlled input to
80this operation. Read all relevant validation, middleware, type constraints, and
81calling code. Determine:
821. Can an attacker reach this code path with controlled input?
832. Are there existing mitigations that prevent exploitation?
843. If exploitable, what is the concrete attack scenario?
85Report back with your conclusion: CONFIRMED, NOT EXPLOITABLE, or NEEDS MORE CONTEXT."
86```
87
88If the agent reports NOT EXPLOITABLE, drop the finding entirely. Do not include it in the report. If CONFIRMED, proceed to write a PoC. If NEEDS MORE CONTEXT, make a judgment call: either investigate further or move it to Hardening with a note about what is uncertain.
89
90### 5. Write Proof of Concept for Each Vulnerability
91
92Every vulnerability must have a minimal PoC that demonstrates exploitability. The format depends on the type of software:
93
94**For a CLI tool:**
95```bash
96# PoC: [vulnerability name]
97# Expected: [what should happen safely]
98# Actual: [what happens due to the vulnerability]
99command --flag "$(malicious_payload)"
100```
101
102**For a library:**
103```go
104// PoC: [vulnerability name]
105package main
106
107import "vulnerable/package"
108
109func main() {
110 // Minimal code that triggers the vulnerability
111 result := package.VulnerableFunction(maliciousInput)
112 // Demonstrate the impact
113}
114```
115
116```rust
117// PoC: [vulnerability name]
118use vulnerable_crate::vulnerable_function;
119
120fn main() {
121 // Minimal code that triggers the vulnerability
122 let result = vulnerable_function(malicious_input);
123 // Demonstrate the impact
124}
125```
126
127**For a server:**
128```bash
129# PoC: [vulnerability name]
130# Step 1: [setup if needed]
131curl -X POST http://localhost:8080/endpoint \
132 -H "Content-Type: application/json" \
133 -d '{"malicious": "payload"}'
134# Expected response: [what safe behavior looks like]
135# Actual response: [what the vulnerability produces]
136```
137
138The PoC must be minimal — only the code necessary to trigger the issue and nothing else.
139
140### 6. Classify Findings
141
142All confirmed vulnerabilities are rated on this scale:
143
144| Severity | Criteria |
145|----------|----------|
146| **High** | Exploitable with no or minimal preconditions. Leads to RCE, authentication bypass, privilege escalation, data breach, or significant data exposure. |
147| **Medium** | Exploitable but requires specific conditions (authenticated attacker, particular configuration, race condition timing). Impact is meaningful but bounded. |
148| **Low** | Exploitable but impact is limited (minor information disclosure, DoS requiring sustained effort, issues only exploitable in non-default configurations). |
149
150Hardening recommendations are not rated on this scale. They are listed separately without severity ratings.
151
152### 7. Write Report
153
154Write the report to `SECURITY_REVIEW.md` in the current working directory with this structure:
155
156```markdown
157# Security Review
158
159**Scope:** {files or directories reviewed}
160**Date:** {date}
161**Languages:** {detected languages}
162**Software type:** {CLI tool / library / server / etc.}
163
164## Summary
165
166{1-3 sentences. State the number of confirmed vulnerabilities found and their severity breakdown. If none found, say so clearly.}
167
168---
169
170## Vulnerabilities
171
172{If no vulnerabilities were found, state: "No confirmed vulnerabilities were identified."}
173
174### HIGH-001: {Finding Title}
175
176**File:** `path/to/file.go:42`
177**Category:** {e.g., Injection, Authentication, Cryptography}
178
179**Description:**
180{What the vulnerability is. Be specific about the data flow: what attacker-controlled input reaches what dangerous operation, and why existing controls do not prevent it.}
181
182**Vulnerable Code:**
183{The specific code snippet containing the vulnerability}
184
185**Proof of Concept:**
186{Minimal PoC demonstrating the vulnerability — commands, code, or HTTP requests}
187
188**Recommendation:**
189{How to fix it, with a corrected code example}
190
191---
192
193### MED-001: {Finding Title}
194
195{same structure}
196
197---
198
199### LOW-001: {Finding Title}
200
201{same structure}
202
203---
204
205## Security Hardening
206
207{Defense-in-depth recommendations that do not address a specific confirmed vulnerability. These are improvements to security posture.}
208
209### {Recommendation Title}
210
211**File:** `path/to/file.go:42` (if applicable)
212
213**Description:**
214{What could be improved and why it strengthens security posture, even though it does not address a specific confirmed vulnerability.}
215
216**Suggestion:**
217{Concrete code or configuration change}
218```
219
220### 8. Present to User
221
222After writing the report, summarize the confirmed vulnerabilities inline. Do not summarize hardening items — they are secondary. Ask if the user wants to discuss any specific finding in detail.
223
224---
225
226## General Checks
227
228Apply these checks regardless of language. Remember: only flag items where you can trace attacker-controlled input to a dangerous operation without existing mitigation.
229
230### Input Validation
231
232- Untrusted input used directly in SQL queries, commands, file paths, or URLs
233- Missing or insufficient length/size limits on inputs
234- Improper handling of Unicode, null bytes, or encoding edge cases
235- Path traversal via `../` or absolute paths in user-supplied filenames
236- SSRF via user-controlled URLs used in outbound requests
237
238### Authentication and Authorization
239
240- Missing authentication on sensitive endpoints
241- Authorization checks that can be bypassed (IDOR, missing ownership checks)
242- Hard-coded credentials, API keys, or tokens
243- Timing-safe comparison not used for secrets (`==` instead of constant-time compare)
244- Session tokens with insufficient entropy or predictable generation
245
246### Cryptography
247
248- Use of broken algorithms (MD5, SHA1 for security purposes, DES, RC4)
249- Hard-coded keys, IVs, or nonces
250- Nonce reuse in AEAD ciphers
251- Use of ECB mode
252- Custom cryptographic implementations instead of vetted libraries
253- Insufficient key lengths (RSA < 2048, symmetric < 128-bit)
254- Missing integrity protection (encryption without authentication)
255
256### Error Handling
257
258- Stack traces, internal paths, or debug info exposed to users
259- Errors that reveal whether a user/resource exists (enumeration)
260- Catch-all error handlers that swallow security-relevant failures
261- Panics or crashes reachable from untrusted input
262
263### Secrets Management
264
265- Secrets logged to stdout/stderr or log files
266- Secrets in source code, config files committed to VCS, or environment variable defaults
267- Secrets not zeroed from memory after use
268- `.env` files, private keys, or credential files in the repository
269
270### Concurrency
271
272- Race conditions in authentication or authorization checks (TOCTOU)
273- Shared mutable state without synchronization
274- Double-spend or duplicate-action vulnerabilities from concurrent requests
275
276### Dependency and Supply Chain
277
278- Dependencies with known CVEs (check go.sum, Cargo.lock)
279- Pinned to mutable refs (branches, `latest`) instead of exact versions or hashes
280- Vendored code that has been modified from upstream
281
282---
283
284## Go Checks
285
286Apply these when reviewing Go code.
287
288### Injection
289
290- `fmt.Sprintf` used to build SQL queries instead of parameterized queries
291- `os/exec.Command` with user-controlled arguments not validated against an allowlist
292- `text/template` used where `html/template` is needed (XSS)
293- String concatenation in `database/sql` query construction
294
295### Error Handling
296
297- Errors discarded with `_ =` on security-critical operations (file permissions, crypto, auth)
298- `defer` closing a resource but ignoring the close error (can mask write failures)
299- `recover()` catching panics broadly, masking security failures
300- Missing error checks on `io.Copy`, `http.Response.Body.Close`
301
302### HTTP and Networking
303
304- Missing TLS configuration or insecure `TLSClientConfig` (`InsecureSkipVerify: true`)
305- `http.DefaultClient` used without timeouts (enables slowloris DoS)
306- Missing `http.MaxBytesReader` on request bodies (memory exhaustion)
307- CORS headers set to `*` or reflecting origin without validation
308- Missing CSRF protection on state-changing endpoints
309- `http.Redirect` with user-controlled URL (open redirect)
310
311### Concurrency
312
313- Race conditions on maps (concurrent read/write without `sync.Map` or mutex)
314- Goroutine leaks from missing context cancellation or unbounded channel sends
315- `sync.WaitGroup` misuse (Add/Done mismatch)
316- Shared slice/map modified across goroutines without synchronization
317
318### Unsafe Operations
319
320- Use of `unsafe` package for pointer arithmetic or type punning
321- `reflect` used to bypass unexported field protections
322- `cgo` calls with unchecked buffer sizes or missing null termination
323- `//go:linkname` used to access internal runtime functions
324
325### Cryptographic Pitfalls
326
327- `math/rand` used where `crypto/rand` is required (token generation, nonces)
328- `crypto/subtle.ConstantTimeCompare` not used for secret comparison
329- Custom `hash.Hash` usage without proper reset between uses
330- `crypto/tls` config missing `MinVersion: tls.VersionTLS12`
331
332### Integer and Memory
333
334- Integer overflow in `make([]byte, userControlledSize)` causing allocation issues
335- Slice bounds not checked before indexing with external values
336- `strconv.Atoi` result used without range validation
337
338### File and OS
339
340- `os.MkdirAll` with overly permissive mode (0777)
341- `os.OpenFile` without validating symlink targets (symlink following)
342- Temporary files created in shared directories without `os.CreateTemp`
343- Missing `filepath.Clean` on user-supplied paths
344
345---
346
347## Rust Checks
348
349Apply these when reviewing Rust code.
350
351### Unsafe Code
352
353- Every `unsafe` block: verify the safety invariants documented and upheld
354- Raw pointer dereferencing without null/alignment checks
355- `std::mem::transmute` used for type punning (verify layout compatibility)
356- `unsafe impl Send/Sync` on types containing raw pointers or non-thread-safe internals
357- `from_raw_parts` / `from_raw_parts_mut` with unchecked length or alignment
358- `ManuallyDrop` or `std::mem::forget` causing resource leaks (file handles, locks)
359- FFI boundaries: missing null checks, buffer size validation, lifetime guarantees
360
361### Error Handling
362
363- `.unwrap()` or `.expect()` on `Result`/`Option` reachable from untrusted input
364- `panic!` in library code reachable from external callers
365- `?` propagation that discards context needed for security decisions
366- `catch_unwind` used as a substitute for proper error handling
367
368### Memory Safety (even in safe Rust)
369
370- Logic errors in index arithmetic leading to out-of-bounds via `.get_unchecked()`
371- `Vec::set_len()` on uninitialized memory
372- Stack overflow via unbounded recursion on attacker-controlled input
373- Large allocations from user-controlled sizes (`Vec::with_capacity(user_input)`)
374
375### Serialization and Parsing
376
377- `serde` deserialization of untrusted input without size limits or depth limits
378- `#[serde(deny_unknown_fields)]` missing on security-critical config structs
379- Custom `Deserialize` implementations with unchecked invariants
380- Deserializing into `enum` variants that trigger different privilege levels
381
382### Web and Network (axum, actix-web, hyper, tokio)
383
384- Missing request body size limits (`tower_http::limit::RequestBodyLimitLayer`)
385- Timeout not configured on server or client connections
386- Missing TLS certificate validation on HTTP clients (`danger_accept_invalid_certs`)
387- Shared mutable state in handlers without `Arc<Mutex<_>>` or `Arc<RwLock<_>>`
388- Missing authentication middleware on protected routes
389- `tower` layers ordered incorrectly (auth after handler, rate limit after auth)
390
391### Concurrency
392
393- `Mutex` poisoning not handled (`lock().unwrap()` on potentially poisoned mutex)
394- `Arc` reference cycles causing memory leaks
395- Deadlock potential from inconsistent lock ordering
396- `tokio::spawn` without `JoinHandle` tracking (silent task failures)
397- Blocking operations in async context (`std::fs` in tokio runtime, `std::thread::sleep`)
398
399### Cryptographic Pitfalls
400
401- `rand::thread_rng()` used where `rand::rngs::OsRng` is needed for cryptographic randomness
402- `ring` or `rustcrypto` primitives used without authenticated encryption
403- Custom serialization of cryptographic keys without constant-time comparison
404- Timing side-channels in comparison operations (`==` on secrets)
405
406### Supply Chain and Build
407
408- `build.rs` executing arbitrary code at compile time
409- `proc_macro` dependencies with network access or file system writes
410- `[patch]` or `[replace]` in `Cargo.toml` overriding dependencies
411- Feature flags that silently disable security features (`#[cfg(not(feature = "tls"))]`)
412
413### Integer Safety
414
415- Arithmetic operations that can overflow/underflow (use `checked_*`, `saturating_*`, or `wrapping_*`)
416- `as` casts that truncate or sign-extend (`u64 as u32`, `i32 as u32`)
417- `usize` used for serialized data sizes across architectures (32 vs 64-bit mismatch)