AppSec Vulnerable Code Screening Cheat Sheet by Language
Purpose: give candidates and reviewers a fast, repeatable way to inspect vulnerable-code snippets under interview pressure without scanners. This page is intentionally biased toward the first 2 to 5 minutes of analysis: what to look at first, what patterns are high signal, and how to explain findings crisply.
Use this page with: AppSec Engineer Code and Weakness Review Drills and Live Code-Review Drills and Answer Guides.
The universal screening pattern
When a snippet lands on screen, scan in this order:
- Where does attacker-controlled input enter? Request params, JSON body, headers, cookies, uploaded files, environment variables, CLI args, queue payloads, DB results, deserialized objects.
- Where are the dangerous sinks? SQL, OS commands, filesystem writes, archive extraction, templates, redirects, authz decisions, crypto calls, serialization, reflection, unsafe native APIs.
- What protects the path? Validation, output encoding, parameterization, allow-lists, authn, authz, object ownership checks, safe defaults, rate limits, audit logs.
- What business action is happening? Money movement, role change, password reset, approval, export, delete, token issuance, tenant switch, webhook trust decision.
- What is the likely impact? Code execution, data theft, cross-tenant access, privilege escalation, account takeover, denial of service, tampering, secret disclosure.
- What exact fix would you make first? Name the vulnerable line, the control you would add, and the regression test you would write.
A good 30-second opening statement
"I would start by identifying the trust boundary and the dangerous sinks. In this snippet, untrusted input reaches [sink] without [control]. The primary issue is [weakness]; the likely impact is [impact]. I would fix it by [precise fix] and add [test/guardrail] so it does not regress."
What you can usually skip on first pass
- harmless constant definitions and obvious DTOs;
- formatting, style, and naming nits;
- imports that are not security-relevant;
- comments unless they reveal hidden trust assumptions;
- framework boilerplate if it does not affect auth, validation, or I/O.
Python
High-signal danger words and APIs
os.system,subprocess.run(..., shell=True),subprocess.Popen(..., shell=True)eval,exec,ast.literal_evalon untrusted input used incorrectly- raw SQL via string formatting,
%,.format(), f-strings pickle.loads,yaml.loadwith unsafe loader,marshal,shelvehashlib.md5,hashlib.sha1for passwords or integrity decisionstempfile.mktemp, unsafe file writes to predictable paths- Flask/Django routes that mutate state without authz/CSRF/object ownership checks
What dangerous sections look like
- f-strings or concatenation around
SELECT,UPDATE,DELETE,ORDER BY - shell helpers that interpolate request params into command strings
- serializers/deserializers fed by cookies, queues, or uploaded files
- password reset, invite acceptance, admin endpoints guarded only by a shared token
- archive processing with no canonical path checks
What to say out loud
- "I see untrusted input flowing into a shell/SQL/deserialize sink."
- "This is structural injection, not only string injection, because
ORDER BY/table names are also attacker-influenced." - "The larger issue is broken authorization or tenant isolation, not just input validation."
Typical safe replacements
- parameterized queries with DB driver placeholders
subprocess.run([...], shell=False, check=True)with allow-listed argumentsyaml.safe_load, neverpicklefor untrusted data- Argon2,
bcrypt, orscryptfor passwords
Java
High-signal danger words and APIs
Runtime.getRuntime().exec,ProcessBuilderwith attacker-influenced args- string-built JDBC / JPA native queries
ObjectInputStream.readObject, XML decoders, risky Jackson polymorphic config- Spring controller methods missing
@PreAuthorizeor object ownership checks MessageDigest.getInstance("MD5")or SHA-1 for passwords/signaturesFiles.write,Paths.getwith user-controlled path elements- open redirects through
redirect:or attacker-controlledLocation
Dangerous section patterns
- repositories loading by
idonly when path also containstenantId - approval or delete endpoints that check authentication but not role or workflow state
- native queries with concatenated
ORDER BY, search, tenant, or status filters - download/export handlers returning entire entity objects or raw stack traces
What to say out loud
- "This looks like IDOR or broken object-level authorization because the lookup ignores tenant or ownership context."
- "I would not stop at the controller annotation; I want service-layer authorization and state-transition checks too."
- "The right remediation is a repository method constrained by tenant plus a policy service, not another inline
ifblock."
Typical safe replacements
findByIdAndTenantId(...)or equivalent object-scoped data access- bean validation + allow-lists for sort/filter fields
PasswordEncoderwith strong algorithms- safer deserialization and strict type handling
C++
High-signal danger words and APIs
system,popen,exec*strcpy,strcat,sprintf,gets, uncheckedmemcpy- raw pointer arithmetic around buffers
- archive extraction with path concatenation
- manual crypto or homegrown token logic
- insecure random sources (
rand) for security decisions - deserialization of attacker-controlled binary formats with weak bounds checks
Dangerous section patterns
- fixed-size char buffers receiving unbounded input
- archive/file extraction logic that joins base dir + entry name blindly
- integer length fields used for allocation/copy without validating range
- unsafe narrowing conversions before buffer use
- network services parsing custom binary protocols without strict framing
What to say out loud
- "I would look for memory-safety bugs and trust-boundary mistakes before syntax details."
- "The extraction path is vulnerable to traversal unless canonicalized against the intended root."
- "Even if this is not obviously exploitable RCE, a denial-of-service or overwrite primitive is still serious."
Typical safe replacements
- safer abstractions (
std::string, bounded APIs) - canonical path validation using filesystem APIs
- strict bounds checking before allocation and copy
- least-privilege runtime and sandboxing where native parsing is unavoidable
TypeScript / JavaScript
High-signal danger words and APIs
eval,new Function, dynamic import from untrusted pathchild_process.exec,execSync,spawnwith shell or interpolated args- template rendering with unescaped HTML
- direct use of
req.query,req.body,req.headersin SQL/NoSQL/redirects - prototype pollution via merge helpers or unsafe deep merge
- JWT verification bugs,
alg=noneanti-patterns, weak secret handling - NoSQL queries built directly from user objects
Dangerous section patterns
- spreading
req.bodyinto trusted objects ({...req.body}) without allow-listing - Mongo queries using attacker-provided JSON directly
- Express middleware checking only
if (user.isAdmin)without strong session or auth source - SSR or template code returning attacker-controlled HTML snippets
What to say out loud
- "I am checking both data injection and object-shape abuse, because JavaScript ecosystems are also vulnerable to prototype pollution and auth bypass through implicit trust in object fields."
- "In Node.js, shell execution and broad object merges are both high-signal danger zones."
Typical safe replacements
- schema validation at boundaries
- allow-listed object mapping instead of mass assignment
- parameterized DB calls and ORM safe APIs
- safe templating defaults and output encoding
PHP
High-signal danger words and APIs
include,require,include_once,require_oncewith user-controlled path- raw
$_GET,$_POST,$_COOKIE,$_REQUESTreaching SQL or file paths unserialize, dynamic function names, variable variables- weak file upload handling,
move_uploaded_fileinto web root md5,sha1for passwords or security tokens- loose comparisons (
==) in auth/token logic shell_exec, backticks,exec,passthru
Dangerous section patterns
- file paths built from request params
- session booleans used as the only control on admin actions
- report export features returning attacker-selected files
- comparison of secrets or auth values with loose equality
- upload handlers trusting extension or client MIME type
What to say out loud
- "I am checking for local file inclusion, traversal, and weak session assumptions first because those are common interview traps in PHP snippets."
- "Loose comparison is dangerous here if token or hash values are compared with
==."
Typical safe replacements
- strict comparisons (
===) - allow-listed template identifiers
password_hash/password_verify- file storage outside web root with server-side generated names
Go
High-signal danger words and APIs
exec.Commandwith attacker-controlled program or arguments- SQL built with
fmt.Sprintfor concatenation - unsafe deserialization or custom parsers without bounds checks
http.HandleFunchandlers mutating state without authz/CSRF checkscrypto/md5,crypto/sha1used for passwords or security decisions- archive extraction or filesystem writes without path normalization
- direct exposure of internal errors in HTTP responses
Dangerous section patterns
- path params or JSON fields passed into SQL or filesystem helpers
- privileged admin endpoints missing actor/role verification
http.ListenAndServewith weak TLS posture for sensitive services- goroutines masking time-of-check/time-of-use state bugs in approval flows
What to say out loud
- "In Go I would still follow the same model: source, sink, authz, state transition, then exact fix."
- "If I see
fmt.Sprintfaround SQL, that is an immediate injection smell."
Typical safe replacements
- prepared statements / query parameterization
- strict object mapping from request DTOs to domain structs
- safe archive extraction helpers and canonical path checks
- explicit authz middleware and policy services
SQL
High-signal danger words and patterns
- dynamic SQL with concatenated user input
EXEC,sp_executesql, procedural dynamic query builders- wildcard privileges and broad grants
- missing tenant filters in multi-tenant tables
- functions or procedures performing privileged actions without caller checks
- ad hoc reporting queries with attacker-controlled
ORDER BY, table, or column names
What dangerous sections look like
- procedure parameters inserted into SQL text directly
- audit or export procedures not scoped by actor or tenant
- grants to application accounts that exceed CRUD needs
- maintenance procedures callable by application identities
What to say out loud
- "I am checking both injection and authorization inside the data layer. Even a safe query can still be a security bug if it ignores tenant or ownership filters."
- "Structural elements such as sort fields, table names, or procedure names must be allow-listed, not escaped."
Typical safe replacements
- parameters for values, allow-lists for structural SQL choices
- least-privilege DB accounts
- views or row-level security where appropriate
- immutable audit patterns for sensitive state changes
One-page answer structure for any language
When the interviewer asks you to explain the snippet, use this shape:
- Call out the trust boundary. "Input comes from request body / path / cookie / queue message."
- Name the sink. "That input reaches SQL / shell / file include / deserializer / approval action."
- Name the weakness precisely. SQL injection, IDOR, broken authz, path traversal, weak crypto, insecure deserialization, mass assignment.
- State the impact in business terms. Data theft, cross-tenant access, admin takeover, workflow abuse, privilege escalation.
- Give the first fix and the durable fix. Parameterize now, then add policy guardrails / tests / lint rules / codeowners / safer abstractions.
- Mention how you would verify. Unit test, negative test, integration test, policy gate, regression rule.
The short list of danger words to memorize
- Execution:
exec,system,shell,Runtime.exec,subprocess,ProcessBuilder,child_process - Deserialization:
pickle,unserialize,readObject, unsafeyaml.load - Crypto:
md5,sha1, custom crypto, static IVs, ECB, hardcoded keys - Filesystem:
include,require,open,fopen,Paths.get, archive extract, temp file helpers - Database: string-built
SELECT/UPDATE/DELETE,ORDER BY,LIMIT, dynamic SQL, raw query APIs - Auth:
isAdmin,role,tenantId,ownerId,approved,reset,invite,token,session - Web: redirect, template, HTML, upload, webhook, callback, origin, CORS
Final coaching note
Interviewers are usually not looking for every issue in the snippet. They are looking for whether you can:
- find the highest-risk issue first;
- explain it in clear engineering language;
- propose a realistic fix;
- show you understand blast radius, trust boundaries, and how to prevent recurrence.
A calm, prioritized answer beats a chaotic list of ten possible bugs every time.