LazyHackers.in — Checklist
🔎 Secure Source Code Review Checklist
Source → sink, item by item: what to grep · the scenario · the finding · the fix
☰ How to use this guide
Secure code review is one discipline: follow the data. A SAST tool flags candidates; a finding is real only when you trace an untrusted source (HTTP param, header, body, file, DB, queue, IPC, env) to a dangerous sink (exec, query, eval, deserialize, file op, redirect) with no effective sanitisation between them. This guide turns every checklist line into what-to-grep + how-to-confirm. Pair with the dynamic checklists (web/API/mobile) to prove exploitability.
# Breadth pass, then trace by hand
semgrep --config p/owasp-top-ten --config p/secrets .
# Map sources/sinks quickly with ripgrep
rg -n --no-heading -e 'request\.|req\.(query|body|params)|\$_(GET|POST|REQUEST)|getParameter' . # sources
rg -n --no-heading -e 'exec|system|eval|query\(|innerHTML|deserialize|readObject|unserialize' . # sinks0 Prep & approach
Get the whole codebase and config, understand the architecture and trust boundaries, and map sources, sinks and the enforcement points for auth/authz before diving in.
Prep & approach — full coverage
| Checklist item | How to review | Outcome |
|---|---|---|
| Full source + build + config + manifests | obtain repo | Complete codebase |
| Architecture/frameworks/trust boundaries | read docs/code | Architecture understood |
| Map sources (untrusted input) | rg for request inputs | Sources mapped |
| Map sinks (dangerous functions) | rg for sinks | Sinks mapped |
| Identify auth/authz enforcement points | locate middleware/guards | Enforcement points mapped |
| Threat-model high-value flows | prioritise flows | High-value flows identified |
| Choose approach (trace + grep + framework) | plan review | Review approach set |
| SAST baseline (verify manually) | semgrep/codeql | SAST baseline |
1 Authentication (code)
Look for missing checks, plaintext/non-constant-time compares, weak hashing, hardcoded creds, and logic that grants access without verifying the password.
rg -n -e 'md5|sha1\(' -e 'password\s*==' -e '==\s*password' -e 'hardcoded|backdoor'
rg -n -e 'if\s*\(\s*user\s*!=\s*null' -e 'verify.*=.*true' # auth-bypass logic smells
# JWT: secret + verification
rg -n -e 'jwt|alg.*none|verify\(|decode\('Authentication (code) — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Auth check missing on protected route | audit route guards | Missing authentication |
| Auth client-side / trusted client claim | trace claim usage | Client-side authentication |
| Plaintext / non-constant-time compare | rg password== | Insecure credential compare |
| Weak password hashing | rg md5/sha1 | Weak password hashing |
| Hardcoded credentials / backdoor | rg secrets | Hardcoded credential |
| JWT sig not verified / none / hardcoded | rg jwt | JWT misuse |
| Token via non-CSPRNG | rg Random/rand | Insecure token generation |
| Reset token predictable/non-expiring/reusable | review reset flow | Weak reset token |
| OTP logic flaws | review OTP code | OTP logic flaw |
| Auth bypass via logic flaw | review auth branches | Authentication bypass |
| No rate limiting at code level | check middleware | Missing rate limiting |
2 Authorization (code)
The big one: ownership and role checks. Find queries using a user-supplied ID without an ownership filter, missing role guards, and mass assignment.
# Object access without ownership filter (IDOR/BOLA in code)
rg -n -e 'findById|getById|where.*id|params\.id|req\.params' # then check ownership filter exists
# Missing role guards / mass assignment
rg -n -e '@PreAuthorize|@Authorize|hasRole|isAdmin' # presence/absence on sensitive fns
rg -n -e 'bind\(|@ModelAttribute|mass.?assign|update\(req\.body|create\(req\.body'Authorization (code) — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Ownership not checked (IDOR/BOLA) | trace ID→query, no filter | Missing object authorisation |
| Role/permission check missing (BFLA) | audit sensitive fns | Missing function authorisation |
| AuthZ on hidden field / client role | trace role source | Client-controlled authorisation |
| Mass assignment binds all fields | rg bind/ModelAttribute | Mass assignment |
| User ID in query w/o ownership filter | review queries | Insecure direct object query |
| Privileged action no re-check | audit privileged paths | Missing privilege re-check |
| AuthZ in UI but bypassable (API/job) | check alternate entries | Authorisation bypass via alt entry |
3 Session management (code)
Session rotation, invalidation, cookie flags and identifier entropy — in the framework's session config and login/logout handlers.
Session management (code) — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| No rotation after login | review login handler | Session fixation |
| Not invalidated on logout/pw change | review logout/pw handlers | Session invalidation missing |
| Cookie flags not set | rg cookie config | Insecure cookie flags |
| Token in localStorage (frontend) | rg localStorage | Token in localStorage |
| Excessive/no timeout | review session config | Excessive session lifetime |
| Predictable session identifier | review ID generation | Predictable session ID |
4 Injection (source → sink)
Trace each source to each sink. String-built SQL, command exec, eval, deserialize, template render, and XML parsing of untrusted data are the high-severity hits.
# SQL string concat (vs parameterized)
rg -n -e 'SELECT .*\+|format.*SELECT|f".*SELECT|query\(.*\$\{|\.raw\('
# Command / code execution on input
rg -n -e 'exec\(|system\(|popen|Runtime\.exec|child_process|shell=True|eval\(|Function\('
# Deserialization
rg -n -e 'readObject|unserialize|pickle\.loads|yaml\.load\b|Marshal\.load|BinaryFormatter'
# XXE: parser without hardening
rg -n -e 'DocumentBuilderFactory|SAXParser|XmlReader|libxml|etree'Injection — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| String-concatenated SQL | rg SELECT+input | SQL injection |
| Dynamic query from request data | trace query build | Dynamic SQL |
| ORM raw query w/ untrusted input | rg .raw( | ORM raw injection |
| NoSQL query from user object | review NoSQL build | NoSQL injection |
| Stored proc with concat input | review proc calls | Stored-proc injection |
| OS command with user input | rg exec/system | OS command injection |
| eval / dynamic code on input | rg eval/Function | Code injection |
| Template render of user input | review template usage | Server-side template injection |
| Insecure deserialization | rg readObject/pickle | Insecure deserialization |
| Reflection / dynamic class load | rg reflection | Unsafe reflection |
| LDAP/XPath/XML from input | review query build | LDAP/XPath injection |
| Header / CRLF injection | rg header set + input | CRLF injection |
| Open redirect | rg redirect+input | Open redirect |
| SSRF (user URL to HTTP client) | trace URL→client | SSRF |
| XXE (external entities enabled) | rg XML parser | XXE |
| Regex from user input (ReDoS) | rg new RegExp+input | ReDoS |
| Log injection | rg log + raw input | Log injection |
5 Output encoding / XSS (code)
Find user data reaching a browser sink without encoding, and disabled auto-escaping.
rg -n -e 'innerHTML|dangerouslySetInnerHTML|v-html|document\.write'
rg -n -e '\|\s*safe|\{\{\{|Html\.Raw|mark_safe|autoescape\s*(off|false)'Output encoding / XSS — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| User input rendered unencoded | trace render | Cross-site scripting |
| innerHTML / dangerouslySetInnerHTML / v-html | rg sinks | DOM XSS sink |
| Auto-escaping disabled | rg |safe/Html.Raw | Disabled auto-escaping |
| Input in JS context / inline handler | review JS context | XSS in JS context |
| Content-Type not set / sniffable | check headers | Content sniffing risk |
| CSV/Excel export no formula guard | review export | CSV formula injection |
6 Cryptography (code)
Weak algorithms, ECB, static keys/IVs, non-CSPRNG and trust-all TLS — grep the crypto API usage.
rg -n -e 'DES|RC4|MD5|SHA1|ECB|Math\.random|new Random\(|InsecureSkipVerify|verify=False|trustAllCerts'Cryptography (code) — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Weak algorithm | rg DES/RC4/MD5/SHA1 | Weak cryptographic algorithm |
| ECB mode | rg ECB | ECB mode |
| Hardcoded key/IV/salt | rg key constants | Hardcoded crypto material |
| Static/predictable IV | rg IV | Static IV |
| Non-CSPRNG for tokens | rg Math.random/rand | Insecure randomness |
| Home-grown crypto | review custom crypto | Custom cryptography |
| Trust-all cert/hostname validation | rg InsecureSkipVerify | Improper cert validation |
| Sensitive data not encrypted at rest | review storage | Unencrypted sensitive data |
| Key stored with ciphertext / in repo | review key location | Key co-located with data |
7 Secrets management (code)
Hardcoded keys, secrets in config/comments/history. Scan the working tree and the full git history.
trufflehog git file://. ; gitleaks detect --source .
rg -n -e 'api[_-]?key|secret|password|BEGIN (RSA|PRIVATE) KEY|AKIA[0-9A-Z]{16}'
git log -p -S 'password' | head # secrets that were committed then removedSecrets management (code) — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Hardcoded keys/passwords/tokens | trufflehog/rg | Hardcoded secret |
| Secrets in committed config | review config files | Secret in config |
| Secrets in source comments | rg comments | Secret in comment |
| Private keys / certs in repo | rg BEGIN KEY | Private key in repo |
| Cloud credentials hardcoded | rg AKIA/cloud keys | Cloud credential in code |
| Connection strings with creds | rg connection string | Embedded DB credential |
| .env / secrets in VCS history | gitleaks / git log -S | Secret in git history |
| Secrets logged/printed | rg log(secret) | Secret in logs |
8 Error handling & logging (code)
Verbose errors to users, sensitive data in logs, swallowed exceptions and fail-open paths.
Error handling & logging — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Verbose errors/stack traces to user | review error handlers | Verbose error disclosure |
| PII/secrets/tokens in logs | rg log + sensitive | Sensitive data in logs |
| Exceptions swallowed silently | rg empty catch | Swallowed exception |
| Fail-open logic on error | review error path | Fail-open access |
| Debug mode/endpoints in prod path | rg debug=true | Debug in production |
| No audit logging on security actions | check audit coverage | Missing audit logging |
9 File handling (code)
Path from user input without canonicalisation, unrestricted uploads, and unsafe archive extraction.
rg -n -e 'new File\(|open\(|fopen|readFile|sendFile|include\(|require\(' # + check input canonicalization
rg -n -e 'getOriginalFilename|move_uploaded_file|MultipartFile|extractall|ZipEntry'File handling (code) — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Path from input w/o canonicalization | trace path build | Path traversal |
| Upload no type/extension/content check | review upload handler | Unrestricted upload |
| Upload to web-accessible/executable path | review storage path | Executable upload location |
| User filename used directly | rg getOriginalFilename | Unsafe filename |
| Archive extraction w/o path checks | rg extractall/ZipEntry | Zip slip |
| Temp file race / insecure temp | review temp creation | Insecure temp file |
| No file-size limit | check size limit | Missing size limit |
10 Business logic (code)
Server-side re-validation, atomicity on financial ops, race conditions, and trusting client-supplied price/amount.
Business logic (code) — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Client-side validation only | check server re-validation | Missing server-side validation |
| Race condition (TOCTOU) | review check-then-act | Race condition |
| Missing atomicity on financial op | review transactions | Non-atomic financial operation |
| Negative/overflow not handled | review numeric handling | Numeric validation flaw |
| Workflow state not enforced | review state machine | Workflow bypass |
| Replay not prevented | check nonce/idempotency | Missing replay protection |
| Trusting client price/amount/qty | trace amount source | Client-controlled value trusted |
11 Dependencies / supply chain
Known-vuln versions, untrusted sources, typosquats and build scripts running untrusted code.
npm audit ; pip-audit ; osv-scanner -r . ; trivy fs . # depending on stackDependencies / supply chain — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Vulnerable versions (CVE) | npm/pip-audit, osv-scanner | Vulnerable dependency |
| Outdated / unmaintained libs | review manifest dates | Outdated dependency |
| Untrusted source / no integrity | check lockfile/hashes | Missing dependency integrity |
| Typosquatted package | review names | Typosquatted dependency |
| Excessive/unused deps | depcheck | Excessive dependencies |
| Transitive vuln not surfaced | osv-scanner -r | Transitive vulnerability |
| Build script runs untrusted code | review build scripts | Unsafe build script |
12 Configuration & hardening
Insecure framework defaults, CORS, missing headers/CSRF, disabled TLS verification, permissive permissions.
rg -n -e 'cors|Access-Control-Allow-Origin|debug\s*=\s*true|csrf.*disable|verify\s*=\s*False|chmod 777'Configuration & hardening — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Insecure framework defaults | review config | Insecure default configuration |
| CORS misconfig (* + creds / reflected) | rg cors | CORS misconfiguration |
| Missing security headers | review middleware | Missing security headers |
| CSRF disabled / not applied | rg csrf | CSRF protection gap |
| TLS verification disabled | rg verify=False | Disabled TLS verification |
| Overly permissive file/dir perms | rg chmod 777 | Permissive permissions |
| Hardcoded env-specific values | review config | Environment value hardcoded |
13 Memory safety (C / C++ / unmanaged)
C/C++/unmanaged only: unbounded copies, missing bounds checks, integer overflow, UAF and format strings.
rg -n -e '\bstrcpy\b|\bstrcat\b|\bsprintf\b|\bgets\b|\bmemcpy\b'
rg -n -e 'printf\s*\(\s*[a-zA-Z_]' # format string: printf(user_input)Memory safety (C/C++) — full coverage
| Checklist item | What to grep / review | Report as |
|---|---|---|
| Unbounded copy (strcpy/sprintf/gets) | rg unsafe funcs | Buffer overflow |
| Missing bounds checks | review index use | Out-of-bounds access |
| Integer overflow → undersized alloc | review size math | Integer overflow |
| Use-after-free / double-free | review lifetimes | Use-after-free |
| Format string vuln | rg printf(var) | Format string vulnerability |
| Off-by-one in loop/buffer | review loop bounds | Off-by-one |
| Unchecked malloc/realloc | review return checks | Unchecked allocation |
L Language-specific gotchas
Match these to the stack — the dangerous sinks and framework footguns per language.
What to grep, by language
| Language | Dangerous sinks & footguns to grep |
|---|---|
| Java/JVM | Runtime.exec, ProcessBuilder, ObjectInputStream.readObject, Jackson/XStream gadgets, Statement+concat, DocumentBuilderFactory/SAXParser (XXE), SpEL/OGNL, missing @PreAuthorize, @ModelAttribute binding, trust-all TrustManager |
| Python | eval/exec/pickle.loads, subprocess(..., shell=True), os.system, string-formatted SQL, yaml.load (non-safe), Jinja2 |safe/autoescape off, flask debug=True |
| JavaScript/Node/TS | eval/Function()/child_process.exec, innerHTML/dangerouslySetInnerHTML, prototype pollution (__proto__ merge), SQL string templates, vm misuse, insecure JWT lib usage, regex from input (ReDoS) |
| PHP | eval/system/exec/shell_exec/passthru, include/require with input (LFI/RFI), unserialize on untrusted data, SQL concat (vs PDO prepared), extract() on request, loose == on auth tokens (type juggling) |
| C#/.NET | Process.Start with input, string-concat SQL, BinaryFormatter, Html.Raw/disabled request validation, XmlReader/XmlDocument with DTD (XXE), missing [Authorize] |
| Go | exec.Command via shell, fmt.Sprintf into SQL, text/template vs html/template, InsecureSkipVerify: true, path join without filepath.Clean |
| Ruby | eval/system/backticks/%x, Marshal.load/unsafe YAML, send/public_send with user method, mass assignment without strong params, string-interpolated SQL |
C Category-specific review
Tailor the review to the component type — the same source→sink discipline, focused on what matters per layer.
By component — full coverage
| Component / item | What to grep / review | Report as |
|---|---|---|
| Web backend: route authz coverage | audit every sensitive route | Missing route authorisation |
| Web backend: CSRF on state-changing routes | check CSRF middleware | CSRF gap |
| Web backend: mass assignment / strong params | review binding | Mass assignment |
| Web backend: template auto-escaping | check escaping | Disabled auto-escaping |
| Web backend: session/cookie config | review config | Insecure session config |
| API: authz per endpoint (BOLA/BFLA) | audit endpoints | Missing API authorisation |
| API: excessive data in serializer | review response models | Excessive data exposure |
| API: input validation/schema | check schemas | Missing input validation |
| API: rate limiting at code/middleware | check throttling | Missing rate limiting |
| API: CORS config | review CORS | CORS misconfiguration |
| Mobile: hardcoded secrets/endpoints | rg code | Hardcoded secret (mobile) |
| Mobile: insecure storage APIs | rg SharedPrefs/NSUserDefaults | Insecure storage |
| Mobile: exported components / URL schemes | review manifest/plist | Exported component |
| Mobile: WebView bridge / file access | rg addJavascriptInterface | WebView misconfig |
| Mobile: cert pinning present & correct | review pinning | Pinning gap |
| Mobile: logging of sensitive data | rg log + sensitive | Sensitive log (mobile) |
✓ Coverage map & how to review
Review sections 0–12 on every codebase, §13 only for C/C++/unmanaged, and apply the language gotchas that match the stack.
| Section | Review on | Focus |
|---|---|---|
| 0–12 | Every codebase | Auth, authz, session, injection, XSS, crypto, secrets, errors, files, logic, deps, config |
| 13 Memory safety | C/C++/unmanaged | Buffer/format/integer/UAF |
| Language gotchas | Match to stack | Per-language dangerous sinks |
| Category | By component | Web backend / API / mobile focus |
Core principle: code review is follow the data, don't just scan. SAST flags candidates; a finding is real only when you trace an untrusted source to a dangerous sink with no effective sanitisation between. Prioritise injection, auth/authz gaps, deserialization and hardcoded secrets — and confirm exploitability (or mark it for dynamic confirmation) rather than reporting raw scanner output.