# owasp-security-code-review

Perform evidence-driven security code reviews across application repositories, services, libraries, and pull requests. Use when Codex needs to audit source code for security flaws, map trust boundaries, verify authentication or authorization, trace untrusted data to sensitive sinks, assess business logic or cryptography, or produce prioritized findings when no narrower language or platform review skill fits.

- **Kind:** skill
- **Source:** https://github.com/SpecterOps/skills
- **Page:** https://forefy.com/skills/15c667c0-b897-44d4-a545-4fd27e5e105f
- **API (JSON + files):** https://forefy.com/api/asr/15c667c0-b897-44d4-a545-4fd27e5e105f

---

## SKILL.md

---
name: owasp-security-code-review
description: Perform evidence-driven security code reviews across application repositories, services, libraries, and pull requests. Use when Codex needs to audit source code for security flaws, map trust boundaries, verify authentication or authorization, trace untrusted data to sensitive sinks, assess business logic or cryptography, or produce prioritized findings when no narrower language or platform review skill fits.
---

# OWASP Security Code Review

Use this skill to perform a manual security review that starts from architecture and follows concrete execution paths. Prefer a narrower language, framework, CI, cloud, or infrastructure review skill when one clearly fits; use this skill for baseline coverage and cross-cutting review logic.

## Review Principles

- Build a threat model before reporting issues: identify actors, assets, trust boundaries, privilege levels, and attacker-controlled inputs.
- Treat entry points, identity decisions, privilege changes, and sensitive data movement as primary anchors.
- Confirm issues end to end from source through transformations and guards to sink or security decision.
- Separate confirmed vulnerabilities from suspicious patterns and unanswered questions.
- Prefer a small number of well-supported findings over speculative issue lists.
- Keep coverage visible: record reviewed surfaces, skipped areas, and assumptions that affect confidence.
- Always create or update one standalone `poc_<finding_slug>.py` artifact per confirmed finding in the review workspace.

## References

- Use the local reference files below during ordinary reviews. Retrieve upstream OWASP pages only when the user asks for source verification or updated guidance.
- Read [references/common-vulnerability-patterns.md](references/common-vulnerability-patterns.md) when reviewing input handling, injection, authentication, authorization, deserialization, XML, or cryptographic implementation patterns.
- Read [references/attack-trees.md](references/attack-trees.md) when mapping multi-step attack paths, reviewing critical business workflows, or turning a threat model into concrete code paths.
- Read [references/owasp-secure-code-review.md](references/owasp-secure-code-review.md) for the OWASP review workflow, source-to-sink tracing, and baseline versus diff-based review prompts.
- Read [references/owasp-input-validation.md](references/owasp-input-validation.md), [references/owasp-sql-injection.md](references/owasp-sql-injection.md), [references/owasp-xss.md](references/owasp-xss.md), [references/owasp-file-upload.md](references/owasp-file-upload.md), [references/owasp-os-command-injection.md](references/owasp-os-command-injection.md), and [references/owasp-nosql-security.md](references/owasp-nosql-security.md) for input and injection-specific patterns.
- Read [references/owasp-authentication.md](references/owasp-authentication.md), [references/owasp-session-management.md](references/owasp-session-management.md), and [references/owasp-authorization.md](references/owasp-authorization.md) for identity and access-control patterns.
- Read [references/owasp-deserialization.md](references/owasp-deserialization.md), [references/owasp-xxe.md](references/owasp-xxe.md), and [references/owasp-cryptographic-storage.md](references/owasp-cryptographic-storage.md) for serialization, XML parser, and cryptographic storage patterns.

## Review Process

1. Review architecture for security anti-patterns.
   - Inventory components, languages, frameworks, storage, external integrations, privileged jobs, and deployment boundaries.
   - Identify trust assumptions such as internal-network trust, shared admin paths, tenant co-mingling, unsafe plugin or deserialization surfaces, dynamic code execution, and secret-bearing services.
   - Note where security controls are centralized and where alternate paths may bypass them.

2. Analyze entry points and input validation.
   - Enumerate HTTP/RPC routes, GraphQL resolvers, message consumers, webhooks, CLI commands, scheduled jobs, file imports, deserializers, and configuration inputs.
   - Trace parsing, normalization, canonicalization, schema checks, type checks, size limits, allowlists, and rejection behavior.
   - Look for alternate encodings, duplicate parameters, path confusion, object binding issues, and validation performed after a dangerous sink.

3. Verify authentication and authorization.
   - Map how identities are established, refreshed, propagated, and revoked across user, service, and background-job flows.
   - Check session, token, API key, mTLS, and service-account validation assumptions.
   - Verify every read, write, export, and state transition enforces the required role, tenant, ownership, and object-level checks, including alternate routes and asynchronous handlers.
   - Test fail-open behavior when middleware, policy engines, or upstream identity data is absent or malformed.

4. Trace data flows.
   - Follow untrusted data to SQL/NoSQL queries, templates, filesystem paths, archives, redirects, outbound requests, command execution, logs, serialization, caches, and client responses.
   - Follow sensitive data such as credentials, tokens, personal data, and keys through storage, telemetry, errors, exports, and third-party boundaries.
   - Record sanitizers, encoders, escaping, parameterization, and privilege boundaries on each path; verify that each control is appropriate for the sink.

5. Analyze business logic.
   - Model critical workflows as states and invariants: approvals, payments, invitations, password resets, account recovery, quotas, entitlements, tenant isolation, and admin actions.
   - Check replay, race, ordering, stale-state, double-spend, partial-failure, and TOCTOU behavior.
   - Look for ways to skip steps, reuse artifacts, change identifiers, or invoke a privileged transition through an unexpected channel.

6. Review cryptographic implementation.
   - Identify password hashing, encryption, signatures, MACs, randomness, key derivation, key storage, certificate validation, and token construction.
   - Verify modern primitives, secure parameters, nonce/IV uniqueness, constant-time comparisons where relevant, key separation, rotation, and failure behavior.
   - Treat custom crypto, hardcoded keys, weak randomness, disabled TLS verification, and unsigned or partially verified tokens as priority review areas.

7. Verify error handling.
   - Check whether errors fail closed at authentication, authorization, validation, and transaction boundaries.
   - Review exception swallowing, fallback behavior, retries, partial commits, default values, verbose responses, stack traces, and secret-bearing logs.
   - Confirm that security-relevant failures are observable without leaking sensitive details.

8. Review configuration and deployment.
   - Inspect defaults and environment parsing for debug modes, CORS, trusted proxies, host validation, cookie flags, security headers, logging, feature flags, and secret loading.
   - Review container/runtime privileges, filesystem permissions, network exposure, cloud/IAM bindings, CI/CD secrets, build-time substitutions, and production-vs-development drift when those artifacts are in scope.
   - Identify insecure defaults that make a secure deployment depend on undocumented operator behavior.

9. Build the PoC artifacts.
   - Create or update one standalone `poc_<finding_slug>.py` file for each confirmed finding.
   - Keep each PoC incremental: print or implement numbered steps for prerequisites, authentication or material acquisition, trigger, impact verification, and cleanup guidance.
   - State attacker position, required permissions, credentials or certificates, environmental dependencies, and any unproven prerequisite before sending requests.
   - Default to dry-run or harmless markers and require an explicit flag for state-changing validation.
   - If a finding has no safe runnable path, still create its per-finding PoC scaffold and explain the missing prerequisite or unsafe step.
   - Validate each script with syntax checks and dry runs, then record which live steps were and were not executed.

## Finding Standard

Report a finding only when the review can state:

- the affected code path with file and line references
- the attacker-controlled input or violated trust assumption
- the missing, bypassed, or incorrect control
- the reachable impact and required prerequisites
- a concrete remediation direction
- a focused regression test or validation step

If a concern lacks a complete path or depends on missing runtime context, label it as an open question or coverage gap instead of a confirmed vulnerability.

## Output

Lead with findings ordered by severity. For each finding, include `Severity`, `Location`, `Issue`, `Exploit Path`, `Impact`, `Remediation`, `Test`, and `PoC Requirements`.

For each confirmed finding, reference the corresponding `poc_<finding_slug>.py` artifact in the report and include the minimum attacker position, required permissions or credentials, environmental conditions, safe default behavior, and example invocation.

After findings, include `Open Questions / Assumptions` and `Coverage`. If no confirmed findings exist, say so explicitly and still state the reviewed surfaces, unresolved risks, and test gaps.

## agents

```

```

## agents/openai.yaml

```yaml
interface:
  display_name: "OWASP Security Code Review"
  short_description: "Run evidence-driven security code reviews"
  default_prompt: "Use $owasp-security-code-review to review this codebase for security flaws and prioritized findings."
```

## references

```

```

## references/attack-trees.md

# Attack Trees

Use attack trees when a high-value asset, sensitive workflow, or suspected weakness depends on multiple steps. Treat the tree as a review aid that turns a threat model into concrete code paths; do not report a vulnerability only because a theoretical branch exists.

## Purpose

Map an attacker goal into the paths, prerequisites, trust-boundary crossings, and controls that make the goal possible or prevent it. Use the result to decide which code paths deserve deep tracing and which assumptions need verification.

## Build the Tree

1. Define the root goal in attacker language.
   - Use goals such as `read another tenant's invoice`, `execute code on the worker`, `reset another user's password`, or `extract stored API keys`.
   - Tie the goal to a concrete asset or violated security invariant.

2. Decompose the goal into OR and AND branches.
   - Use OR branches for alternate routes to the same outcome.
   - Use AND branches when multiple conditions must all hold, such as `obtain token` and `bypass object check`.
   - Include alternate entry points, async handlers, imports, exports, and operational paths rather than only the primary UI flow.

3. Attach evidence to each branch.
   - Record the route, function, job, parser, policy decision, storage call, or sink that implements the step.
   - Record attacker capability, required state, trust boundary, and current control.
   - Mark unknowns explicitly instead of assuming a branch is reachable.

4. Trace each viable leaf through the code.
   - Follow source, parsing, normalization, validation, authorization, state changes, and sink.
   - Verify whether controls are present at every boundary crossing.
   - Check whether an earlier control can be bypassed through another branch.

5. Convert the tree into review outcomes.
   - Report a finding only when a path is reachable and impact is demonstrated.
   - Record blocked branches as verified controls.
   - Record unresolved branches as open questions or coverage gaps.
   - Add regression tests for the shortest realistic attack path and for the control that should block it.

## Tree Template

```text
Root goal: <attacker outcome>
Asset or invariant: <what must remain protected>
Attacker: <identity and capabilities>

OR
- Path A: <route or workflow>
  - Preconditions:
  - Code evidence:
  - Control expected:
  - Result:
- Path B: <route or workflow>
  - AND
    - Step 1:
    - Step 2:
  - Preconditions:
  - Code evidence:
  - Control expected:
  - Result:
```

## Review Prompts

- What is the shortest path from an external input to the protected asset?
- Which branches cross authentication, authorization, tenant, or privilege boundaries?
- Which branch depends on stale state, replay, race conditions, or partial failure?
- Which branch uses a different route, job, import, export, or admin surface than the expected workflow?
- Which control is assumed rather than enforced in the code path?
- Which blocked branches have tests proving that the control remains effective?

## OWASP Basis

Use this reference with the [OWASP Secure Code Review Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secure_Code_Review_Cheat_Sheet.html) threat-based review guidance, which calls for mapping potential attack paths through the application, and the [OWASP Threat Modeling Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Threat_Modeling_Cheat_Sheet.html), which structures analysis around system modeling, threat identification, mitigation, and validation.

## references/common-vulnerability-patterns.md

# Common Vulnerability Patterns

Use this reference during manual review when a code path reaches a common security sink or security decision. Base findings on concrete sources, transformations, controls, and sinks rather than on pattern matching alone.

## Contents

- Input validation
- Injection
- Authentication and session management
- Access control
- Deserialization and XML
- Cryptographic implementation
- OWASP source map

## Input Validation

Review all externally influenced inputs, including browser requests, API calls, files, queues, partner feeds, webhooks, and configuration values that can cross a trust boundary.

Check for:

- missing server-side validation or reliance on client-side checks
- validation performed after parsing, persistence, rendering, or another dangerous sink
- denylist-only filtering instead of allowlists for structured fields
- missing syntactic validation for types, formats, lengths, ranges, and enumerated values
- missing semantic validation for business rules such as date ordering, amount bounds, tenant ownership, or state transitions
- inconsistent normalization or Unicode handling before comparison, lookup, or policy checks
- weak regexes that do not anchor the full input or that introduce ReDoS risk
- upload flows that trust filenames, extensions, headers, archive paths, or user-selected storage locations

Expect:

- validation as early as possible after data crosses the boundary
- server-side enforcement even when client-side validation exists for UX
- allowlists for structured inputs and fixed option sets
- explicit minimum and maximum lengths, numeric ranges, and schema checks
- sink-specific defenses in addition to validation; do not treat input validation as the primary defense for SQL injection or XSS

## Injection

### SQL Injection

Look for:

- string concatenation, interpolation, or format strings in SQL statements
- dynamic WHERE, ORDER BY, LIMIT, table, or column fragments built from user input
- stored procedures that concatenate query text internally
- ORM escape hatches that accept raw query fragments

Expect:

- prepared statements or parameterized queries for data values
- safely constructed stored procedures only when they preserve parameterization
- allowlists for unavoidable identifiers or sort directions that cannot be bound as values
- escaping only as a last-resort supplemental control, not the primary defense

### Cross-Site Scripting

Look for:

- untrusted data rendered into HTML, attributes, JavaScript, CSS, URLs, templates, or client-side DOM operations
- unsafe DOM sinks such as `innerHTML`, `outerHTML`, `document.write`, or string-built event handlers
- rich-text rendering without a dedicated sanitization library
- output encoding that does not match the destination context
- code that relies only on CSP or framework defaults while bypassing their safe rendering APIs

Expect:

- context-appropriate output encoding at the final rendering sink
- safe DOM sinks such as `textContent` or `value` where possible
- hardcoded innocuous attribute names when assigning attributes
- dedicated HTML sanitization for intentionally allowed rich content

### Path Traversal and File Handling

Look for:

- user-controlled path segments, filenames, archive member names, or temporary file names
- path joins that accept `..`, absolute paths, encoded traversal, or alternate separators
- upload handlers that let the client choose storage paths or preserve attacker-controlled filenames
- archive extraction without validating target paths and expanded size
- files stored inside the webroot or with executable permissions without a clear requirement

Expect:

- server-generated storage names and server-selected storage paths
- allowlisted file types plus content-based validation where files are accepted
- storage outside the webroot or on a separate host when possible
- least-privilege filesystem permissions
- explicit checks before archive extraction and downstream processing

### Command Injection

Look for:

- shell execution, process spawning, or system utilities that receive user-controlled input
- string-built commands, shell metacharacters, and user-selected executable names or flags
- code that escapes shell input but still allows argument injection
- privileged processes invoking commands when a library API would suffice

Expect:

- library APIs instead of OS commands whenever possible
- structured process APIs that keep the executable and each argument separate
- allowlists for commands and arguments when commands cannot be avoided
- end-of-options handling where supported, such as `--` before attacker-influenced operands
- least-privilege execution and isolated service accounts

### NoSQL Injection

Look for:

- raw client objects or operators merged into NoSQL queries
- string-built query-language expressions or JavaScript evaluation features
- attacker control over operators such as `$where`, comparison operators, or aggregation stages
- untyped query construction and missing parameter binding in drivers or ODMs
- administrative interfaces or databases exposed without authentication

Expect:

- typed, structured driver or ODM query APIs
- explicit allowlists for accepted fields, operators, filters, and sort keys
- schema and type validation before query construction
- rejection of raw operator objects and executable query fragments from clients

## Authentication and Session Management

Review identity establishment, credential handling, session creation, session renewal, logout, password reset, account recovery, and re-authentication for sensitive operations.

Check for:

- inconsistent authentication enforcement across routes, RPC methods, background jobs, and alternate entry points
- credentials or authentication tokens logged, persisted insecurely, or transmitted outside TLS
- verbose login or recovery responses that reveal account existence
- missing re-authentication after password resets, recovery, suspicious activity, or privilege-sensitive actions
- weak session identifiers, predictable values, or tokens containing sensitive data
- session IDs accepted through URLs or alternate channels when cookies are the intended mechanism
- missing `Secure`, `HttpOnly`, or `SameSite` cookie settings where browser cookies are used
- sessions that are not invalidated on logout, timeout, password change, or account state change
- session IDs not regenerated after authentication or any privilege level change

Expect:

- generic authentication failure responses
- strong password storage and secure transport for credentials
- cryptographically random session IDs with sufficient entropy and meaningless client-side contents
- cookie-based session exchange over TLS with secure cookie attributes
- strict session handling that rejects IDs the server did not generate
- session renewal on authentication and privilege transitions

## Access Control

Model authorization as subject, action, object, tenant, and environment conditions. Verify both horizontal and vertical privilege boundaries.

Check for:

- missing object-level checks after a user is authenticated
- role checks without ownership, tenant, relationship, or resource-state checks
- authorization enforced only in the UI or client
- predictable or tamperable identifiers used without resource authorization
- alternate routes, exports, batch handlers, static resources, or background jobs that bypass the normal policy layer
- fail-open behavior on missing policy data, exceptions, or framework misconfiguration
- permissions broader than required for the user or service role

Expect:

- deny-by-default behavior
- server-side authorization on every request and every sensitive state transition
- least privilege across users, services, and administrative functions
- centralized policy decisions with explicit object-level and tenant-level checks
- safe failure handling and audit logging for denied access
- regression tests for unauthorized reads, writes, and privilege changes

## Deserialization and XML

### Insecure Deserialization

Look for:

- native object deserialization of untrusted input from requests, cookies, queues, caches, files, or database fields
- deserializers that let the data stream choose the target type or class
- unsafe library modes, polymorphic type handling, gadget-capable formats, or domain objects that should never be deserialized
- signed data that is verified after deserialization instead of before it

Expect:

- safer data formats and explicit schemas instead of native object graphs where possible
- strict allowlists for allowed types when deserialization is unavoidable
- integrity verification before deserialization when signed payloads are used
- language-specific hardening for high-risk APIs and libraries

### XML External Entity

Look for:

- XML parsers that accept untrusted XML without explicit parser hardening
- DTD support, external entity resolution, external DTD loading, XInclude, or schema imports from untrusted locations
- XML inputs that can reach filesystem reads, internal network requests, or parser expansion behavior

Expect:

- DTDs disabled completely whenever possible
- external entities and external DTD loading disabled when DTD support cannot be removed
- parser-specific hardening verified in the actual library and version in use
- regression tests for file disclosure, SSRF, and entity expansion payloads

## Cryptographic Implementation

Review the protected asset, threat model, algorithm choice, mode, randomness, key lifecycle, and failure behavior together.

Check for:

- custom cryptographic algorithms or protocols
- outdated algorithms, weak key sizes, ECB mode, unauthenticated encryption, or insecure padding choices
- hardcoded keys, reused IVs or nonces, predictable randomness, or keys stored beside ciphertext
- missing certificate validation or hostname verification
- encryption used without integrity protection
- tokens, reset links, IVs, session IDs, or keys generated with non-cryptographic randomness
- missing key rotation, separation, revocation, or access controls

Expect:

- standard, maintained cryptographic libraries
- AES with an authenticated mode such as GCM or CCM for symmetric encryption where applicable
- modern asymmetric choices such as Curve25519, or RSA with at least 2048-bit keys when RSA is required
- secure random generation for keys, IVs, nonces, session IDs, and recovery tokens
- key storage and rotation designed separately from ciphertext storage
- explicit integrity and authenticity checks in addition to confidentiality

## Detailed Local References

Use these local references instead of retrieving the upstream cheat sheets during ordinary reviews:

- [owasp-secure-code-review.md](owasp-secure-code-review.md)
- [owasp-input-validation.md](owasp-input-validation.md)
- [owasp-sql-injection.md](owasp-sql-injection.md)
- [owasp-xss.md](owasp-xss.md)
- [owasp-file-upload.md](owasp-file-upload.md)
- [owasp-os-command-injection.md](owasp-os-command-injection.md)
- [owasp-nosql-security.md](owasp-nosql-security.md)
- [owasp-authentication.md](owasp-authentication.md)
- [owasp-session-management.md](owasp-session-management.md)
- [owasp-authorization.md](owasp-authorization.md)
- [owasp-deserialization.md](owasp-deserialization.md)
- [owasp-xxe.md](owasp-xxe.md)
- [owasp-cryptographic-storage.md](owasp-cryptographic-storage.md)

## references/owasp-authentication.md

# OWASP Authentication

Use this reference when reviewing login, password change, password recovery, MFA, sensitive actions, identity proofing, or credential storage and comparison.

## Review Checks

- Confirm sensitive internal or backend accounts cannot authenticate through public frontends.
- Check password policy for adequate minimum length, long passphrase support, no silent truncation, and breached-password blocking.
- Verify password comparison uses framework/library primitives with constant-time behavior where relevant.
- Require current credentials or equivalent re-authentication before changing passwords, email addresses, payment details, or trusted devices.
- Trigger re-authentication after password resets, account recovery, suspicious activity, or other high-risk events.
- Keep login and authenticated traffic on TLS and avoid account-enumerating responses.

## Pattern Examples

### Account enumeration

```ts
// Vulnerable
if (!user) return res.status(404).json({ error: "user not found" });
if (!verify(password, user.hash)) return res.status(401).json({ error: "wrong password" });
```

```ts
// Safer
if (!user || !verify(password, user.hash)) {
  return res.status(401).json({ error: "invalid credentials" });
}
```

### Password change without re-authentication

```python
# Vulnerable
@app.post("/account/password")
def change_password(user, body):
    users.set_password(user.id, body["new_password"])
```

```python
@app.post("/account/password")
def change_password(user, body):
    if not verify_password(body["current_password"], user.password_hash):
        raise Unauthorized("reauthentication required")
    users.set_password(user.id, validate_new_password(body["new_password"]))
    sessions.invalidate_all(user.id)
```

### Unsafe password comparison

```php
// Vulnerable
if ($storedHash == hash("sha256", $_POST["password"])) { ... }

// Safer
if (password_verify($_POST["password"], $storedHash)) { ... }
```

## Review Prompts

- Can error messages, timing, or recovery flows reveal whether an account exists?
- Do sensitive actions require fresh authentication rather than only an old session?
- Are password reset and recovery artifacts single-use, time-limited, and invalidated after success?
- Are authentication state changes followed by session rotation or invalidation?

## Source

Local summary based on the OWASP Authentication Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html`

## references/owasp-authorization.md

# OWASP Authorization

Use this reference when reviewing role checks, object ownership, tenant isolation, IDOR, admin actions, static resources, background jobs, and policy-engine integration.

## Review Checks

- Separate authentication from authorization: a known identity is not automatically allowed to perform every action.
- Enforce least privilege horizontally and vertically.
- Deny by default when no policy rule matches.
- Validate permission on every request, alternate route, background action, export, and static resource.
- Perform checks on the server side, close to the resource or state transition.
- Verify object-level and tenant-level checks for user-controlled IDs.
- Fail closed on missing policy data, exceptions, and middleware misconfiguration.

## Pattern Examples

### IDOR through user-controlled identifier

```ts
// Vulnerable
app.get("/accounts/:id", requireLogin, async (req, res) => {
  res.json(await accounts.get(req.params.id));
});
```

```ts
// Safer
app.get("/accounts/:id", requireLogin, async (req, res) => {
  const account = await accounts.get(req.params.id);
  if (!canReadAccount(req.user, account)) throw new Forbidden();
  res.json(account);
});
```

### Client-side admin control only

```js
// Vulnerable: hiding a button is not authorization.
if (!currentUser.isAdmin) hideDeleteButton();
```

```ts
// Safer: enforce on the server.
app.delete("/users/:id", requireLogin, requireRole("admin"), deleteUser);
```

### Fail-open policy handling

```python
# Vulnerable
try:
    allowed = policy_engine.check(user, action, resource)
except Exception:
    allowed = True
```

```python
try:
    allowed = policy_engine.check(user, action, resource)
except Exception:
    allowed = False
if not allowed:
    raise Forbidden()
```

## Review Prompts

- What is the subject, action, object, tenant, and environmental condition for this decision?
- Can a user change a resource ID and reach another tenant's data?
- Does an alternate export, batch, or async path repeat the same object-level check?
- Are static files and cloud objects protected by the same policy model?
- Do authorization failures leave partial state changes behind?

## Source

Local summary based on the OWASP Authorization Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html`

## references/owasp-cryptographic-storage.md

# OWASP Cryptographic Storage

Use this reference when reviewing data-at-rest encryption, key handling, IVs/nonces, token generation, password storage decisions, or custom cryptographic code.

## Review Checks

- Start from the threat model and determine which layer must protect the asset.
- Avoid storing sensitive data when the application can avoid it.
- Use maintained libraries and standard algorithms rather than custom cryptography.
- Prefer authenticated encryption modes such as GCM or CCM.
- Use cryptographically secure randomness for keys, nonces, IVs, session IDs, and recovery tokens.
- Keep keys separate from ciphertext and define generation, rotation, revocation, backup, and access controls.
- Do not use reversible encryption for password storage.

## Pattern Examples

### Static key and ECB mode

```python
# Vulnerable
KEY = b"0123456789abcdef"
cipher = AES.new(KEY, AES.MODE_ECB)
ciphertext = cipher.encrypt(pad(secret, 16))
```

```python
# Safer
key = key_manager.get_data_key("customer-records")
nonce = secrets.token_bytes(12)
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
ciphertext, tag = cipher.encrypt_and_digest(secret)
```

### Predictable token generation

```ts
// Vulnerable
const resetToken = Math.random().toString(36).slice(2);
```

```ts
// Safer
const resetToken = crypto.randomBytes(32).toString("base64url");
```

### Encrypting passwords

```python
# Vulnerable
stored_password = aes_encrypt(user_password, key)
```

```python
# Safer
stored_password = password_hasher.hash(user_password)
```

## Review Prompts

- What attacker is the encryption intended to stop: stolen disk, DB dump, service compromise, or operator misuse?
- Is confidentiality paired with integrity and authenticity?
- Are nonces or IVs unique for each encryption operation?
- Are keys stored, rotated, and revoked independently from the encrypted data?
- Does any custom crypto or disabled certificate validation bypass the library's security guarantees?

## Source

Local summary based on the OWASP Cryptographic Storage Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html`

## references/owasp-deserialization.md

# OWASP Deserialization

Use this reference when reviewing native object serialization, polymorphic JSON/XML, YAML loaders, signed blobs, caches, queue messages, or framework features that rebuild objects from untrusted data.

## Review Checks

- Prefer simple data formats plus explicit schemas over native object graphs.
- Search for dangerous APIs such as Python `pickle`, unsafe PyYAML loaders, Java `ObjectInputStream`, PHP `unserialize`, .NET `BinaryFormatter`, and type-enabled JSON serializers.
- Check whether the data stream controls the type or class being instantiated.
- Verify signatures or MACs before deserialization, not after.
- Allowlist expected types when deserialization is unavoidable.
- Review sensitive fields that should never be serialized or restored from user data.

## Pattern Examples

### Python pickle

```python
# Vulnerable
payload = base64.b64decode(request.json["blob"])
obj = pickle.loads(payload)
```

```python
# Safer
payload = json.loads(request.json["blob"])
obj = validate_order_schema(payload)
```

### Unsafe YAML loader

```python
# Vulnerable
config = yaml.load(user_yaml, Loader=yaml.Loader)
```

```python
# Safer
config = yaml.safe_load(user_yaml)
validate_config_schema(config)
```

### Java native deserialization

```java
// Vulnerable
ObjectInputStream in = new ObjectInputStream(request.getInputStream());
Object value = in.readObject();
```

```java
// Safer concept: restrict the allowed classes before object construction.
AllowedTypeObjectInputStream in =
    new AllowedTypeObjectInputStream(request.getInputStream(), Set.of(OrderDto.class));
OrderDto value = (OrderDto) in.readObject();
```

## Review Prompts

- Can the attacker choose the serialized type, class metadata, or gadget chain?
- Is the payload from a request, cookie, queue, cache, upload, or lower-trust database?
- Does the application verify integrity before rebuilding objects?
- Would a schema-driven DTO or plain JSON structure remove the need for native deserialization?

## Source

Local summary based on the OWASP Deserialization Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html`

## references/owasp-file-upload.md

# OWASP File Upload

Use this reference when reviewing uploads, imports, archive extraction, generated files, or any path built from attacker-influenced filenames.

## Review Checks

- Validate after decoding filenames and paths.
- Use allowlisted extensions and content-aware validation; never trust `Content-Type` alone.
- Generate storage names server-side and keep user-supplied names as metadata only.
- Store files outside the webroot or on a separate host where possible.
- Apply size limits before and after decompression, and validate archive member paths.
- Check permissions, antivirus/sandbox processing, CSRF protection, and safe download authorization.

## Pattern Examples

### Original filename used as storage path

```python
# Vulnerable
dest = os.path.join(UPLOAD_DIR, upload.filename)
upload.save(dest)
```

```python
# Safer
ext = detect_allowed_extension(upload)
storage_name = f"{uuid.uuid4()}.{ext}"
dest = os.path.join(PRIVATE_UPLOAD_DIR, storage_name)
upload.save(dest)
```

### Trusting MIME type

```ts
// Vulnerable
if (file.mimetype === "image/png") {
  await save(file);
}
```

```ts
// Safer
const type = detectFileSignature(file.buffer);
if (!ALLOWED_IMAGE_TYPES.has(type) || file.size > MAX_IMAGE_BYTES) {
  throw new BadRequest("invalid image");
}
await saveOutsideWebroot(randomStorageName(type), file.buffer);
```

### Archive traversal

```python
# Vulnerable
zip_file.extractall(EXTRACT_DIR)
```

```python
# Safer
base = EXTRACT_DIR.resolve()
for member in zip_file.infolist():
    target = (base / member.filename).resolve()
    if target != base and base not in target.parents:
        raise BadRequest("invalid archive path")
    if member.file_size > MAX_MEMBER_BYTES:
        raise BadRequest("archive member too large")
```

## Review Prompts

- Can the attacker choose a filename, path, extension, or archive member path?
- Can uploaded content execute, render active content, overwrite files, or exhaust storage?
- Does retrieval require authorization, or are uploaded files public by default?
- Does any downstream parser receive untrusted files without hardening?

## Source

Local summary based on the OWASP File Upload Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html`

## references/owasp-input-validation.md

# OWASP Input Validation

Use this reference when reviewing any data that crosses a trust boundary. Validate early, on the server, at both syntactic and semantic levels.

## Review Checks

- Identify every untrusted source: HTTP input, files, queue messages, partner feeds, webhooks, database reads from lower-trust stores, and environment/config values.
- Check type conversion, length limits, ranges, enum allowlists, full-string regex anchoring, normalization, and Unicode handling.
- Verify semantic rules such as `start_date <= end_date`, positive amounts, allowed state transitions, and tenant ownership.
- Treat denylist filtering as supplemental only. It must not replace allowlists for structured data.
- Confirm validation happens before persistence, rendering, command execution, path construction, or policy decisions.

## Pattern Examples

### Client-side only validation

```ts
// Vulnerable: browser checks are bypassable.
const role = req.body.role;
await users.create({ email: req.body.email, role });
```

```ts
// Safer: enforce allowed values on the server.
const role = String(req.body.role);
if (!["member", "viewer"].includes(role)) {
  throw new BadRequest("invalid role");
}
await users.create({ email: validateEmail(req.body.email), role });
```

### Denylist instead of allowlist

```python
# Vulnerable: misses alternate encodings and legitimate cases.
if "<script>" in comment or "1=1" in comment:
    reject()
```

```python
# Safer: validate the field shape, then encode for the eventual sink.
comment = normalize_text(request.json["comment"])
if len(comment) > 2000:
    raise BadRequest("comment too long")
```

### Missing semantic validation

```python
# Vulnerable: dates parse, but the business rule is unchecked.
start = parse_date(body["start"])
end = parse_date(body["end"])
create_booking(start, end)
```

```python
start = parse_date(body["start"])
end = parse_date(body["end"])
if end < start:
    raise BadRequest("end must not precede start")
create_booking(start, end)
```

## Review Prompts

- Which inputs are accepted because the client UI normally constrains them?
- Does the code normalize before comparison and authorization?
- Are regexes anchored and bounded, or can they trigger ReDoS?
- Are free-form text fields handled with sink-specific output encoding rather than over-aggressive filtering?
- Do file and archive inputs get size, path, type, and decompression checks?

## Source

Local summary based on the OWASP Input Validation Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html`

## references/owasp-nosql-security.md

# OWASP NoSQL Security

Use this reference when reviewing MongoDB, CouchDB, Cassandra, DynamoDB, Elasticsearch-like query DSLs, ODMs, or any structured query object built from attacker input.

## Review Checks

- Reject raw client-supplied query fragments, operators, aggregation stages, and executable expressions.
- Validate types and allowlisted fields before constructing filters or sort clauses.
- Review driver and ODM escape hatches, `eval`-like features, and server-side scripting.
- Check authentication, TLS, network exposure, admin interfaces, secrets, backups, and least-privilege database roles.
- Look for operator injection through JSON objects even when no strings are concatenated.

## Pattern Examples

### Raw filter passthrough

```js
// Vulnerable: attacker can submit operators such as {"$ne": null}.
const user = await users.findOne(req.body.filter);
```

```js
// Safer
const email = String(req.body.email);
const user = await users.findOne({ email });
```

### Executable query fragment

```js
// Vulnerable
const filter = eval("(" + req.query.filter + ")");
db.collection("users").find(filter);
```

```js
// Safer
const allowedFields = new Set(["email", "status"]);
const field = String(req.query.field);
if (!allowedFields.has(field)) throw new BadRequest("invalid field");
db.collection("users").find({ [field]: String(req.query.value) });
```

### Unbounded operator support

```ts
// Vulnerable
const query = { ...req.body };
await collection.find(query).toArray();
```

```ts
// Safer
const query = {
  status: validateEnum(req.body.status, ["active", "disabled"]),
  tenantId: authenticatedTenantId
};
await collection.find(query).toArray();
```

## Review Prompts

- Can the client inject `$where`, `$regex`, `$expr`, or equivalent operators?
- Does the query layer accept raw JSON or DSL fragments?
- Is the database reachable from the public network or running with default/open access?
- Are service accounts separated for read, write, admin, and backup operations?

## Source

Local summary based on the OWASP NoSQL Security Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/NoSQL_Security_Cheat_Sheet.html`

## references/owasp-os-command-injection.md

# OWASP OS Command Injection Defense

Use this reference when reviewing shell execution, process spawning, CLI wrappers, build scripts, or utilities that pass attacker-controlled values to system commands.

## Review Checks

- Prefer language/library APIs over OS commands.
- When commands are unavoidable, keep the executable fixed and pass arguments as a structured array.
- Validate commands and arguments with allowlists and bounded formats.
- Check for argument injection even when shell metacharacters are escaped.
- Use end-of-options markers such as `--` where supported.
- Verify the process runs with the lowest privileges needed.

## Pattern Examples

### String-built shell command

```ts
// Vulnerable
exec("convert " + req.body.filename + " output.png");
```

```ts
// Safer
const input = validateBasename(req.body.filename);
spawn("convert", ["--", input, "output.png"], { shell: false });
```

### Command selection from user input

```python
# Vulnerable
subprocess.run([request.json["tool"], request.json["target"]])
```

```python
tool = request.json["tool"]
if tool not in {"ping", "traceroute"}:
    raise BadRequest("unsupported tool")
target = validate_hostname(request.json["target"])
subprocess.run([tool, "--", target], check=True)
```

### Escaped but still injectable argument

```php
// Still risky: user can inject another curl option.
system("curl " . escapeshellarg($url));
```

```php
// Better: fix command options and separate the operand.
system("curl -- " . escapeshellarg($url));
```

## Review Prompts

- Can a library API replace the command entirely?
- Is the attacker choosing the executable, flags, working directory, or environment?
- Can a value beginning with `-` become an unintended option?
- Does the process inherit privileged environment variables or filesystem access?

## Source

Local summary based on the OWASP OS Command Injection Defense Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html`

## references/owasp-secure-code-review.md

# OWASP Secure Code Review

Use this reference to choose review scope, organize evidence, and keep manual review centered on code paths that automated tools often miss.

## Review Modes

- Use a baseline review for new applications, major releases, legacy onboarding, compliance work, or post-incident review.
- Use a diff-based review for pull requests, commits, feature delivery, and routine security regression checks.
- Escalate from diff-based to baseline review when a change introduces a new trust boundary, new integration, new privilege path, or evidence of systemic control gaps.

## Baseline Sequence

1. Map architecture, components, assets, trust boundaries, and deployment assumptions.
2. Enumerate entry points and verify server-side validation.
3. Verify authentication and authorization at each path.
4. Trace untrusted and sensitive data through processing to sinks.
5. Model critical business workflows and invariants.
6. Review cryptographic implementations and key handling.
7. Check fail-closed error handling and security logging.
8. Inspect configuration, secrets, runtime privileges, and deployment drift.

## Diff-Based Sequence

1. Identify the security controls touched by the change.
2. Identify new or widened attack paths.
3. Verify changed trust-boundary crossings.
4. Review new integrations, parsers, stores, and privileged actions.
5. Check for regressions in existing auth, validation, and logging behavior.
6. Apply the relevant sink-specific references in this directory.

## Evidence Pattern

Trace each suspected issue as:

```text
source -> parsing -> validation -> authorization -> transformation -> sink -> impact
```

Record:

- attacker capability and required state
- exact route, job, function, or parser
- existing controls and bypass conditions
- affected asset or invariant
- test case that proves the issue or proves the control

## Pattern Examples

### Missing alternate-path review

```python
# Primary route enforces ownership.
@app.get("/invoices/{invoice_id}")
def get_invoice(invoice_id, user):
    return invoices.get_for_user(invoice_id, user.id)

# Export path skips the same check.
@app.get("/exports/invoices/{invoice_id}")
def export_invoice(invoice_id, user):
    return invoices.get(invoice_id)
```

Review both routes because a single missed authorization check defeats the protected resource.

### Incomplete data-flow tracing

```ts
const filename = req.query.name;
const normalized = sanitize(filename);
audit.log(normalized);
return fs.readFileSync(path.join(REPORT_DIR, normalized));
```

Do not stop at `sanitize()`. Verify whether the sanitizer is correct for a filesystem path sink, whether canonicalization happens before comparison, and whether the resolved path stays under `REPORT_DIR`.

### Business-logic bypass

```ts
if (order.status === "paid") {
  ship(order);
}

// Separate admin helper can call ship() without checking payment state.
```

Trace every path that can reach the state transition, not only the normal workflow.

## Review Prompts

- Which assets would matter most if confidentiality, integrity, or availability failed?
- Which trust boundaries were added or changed?
- Which security controls are centralized, and which alternate paths bypass them?
- Which suspicious patterns are only scanner hints, and which are complete exploit paths?
- Which unresolved assumptions should be recorded as coverage gaps rather than findings?

## Source

Local summary based on the OWASP Secure Code Review Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/Secure_Code_Review_Cheat_Sheet.html`

## references/owasp-session-management.md

# OWASP Session Management

Use this reference when reviewing session IDs, cookies, token exchange, session storage, logout, fixation, timeout, and privilege transitions.

## Review Checks

- Treat a session ID as equivalent to the authenticated user's strongest credential for the lifetime of the session.
- Require cryptographically random, meaningless identifiers with adequate entropy.
- Keep server-side state out of the client-visible session ID unless using a separately reviewed signed/encrypted token design.
- Prefer cookie-based session exchange and reject session IDs from URLs or alternate channels when cookies are expected.
- Set `Secure`, `HttpOnly`, and appropriate `SameSite` attributes.
- Rotate session IDs after login, password changes, role changes, and other privilege transitions.
- Invalidate sessions on logout, timeout, password reset, account disablement, and re-authentication events.

## Pattern Examples

### Predictable session ID

```python
# Vulnerable
session_id = f"{user.id}-{int(time.time())}"
```

```python
# Safer
session_id = secrets.token_urlsafe(32)
session_store.put(session_id, {"user_id": user.id})
```

### Session ID in URL

```html
<!-- Vulnerable: leaks into history, logs, and referrers -->
<a href="/account?sid=abc123">Account</a>
```

```http
Set-Cookie: id=<opaque-token>; Secure; HttpOnly; SameSite=Lax; Path=/
```

### Missing rotation after login

```ts
// Vulnerable: anonymous session survives privilege change.
req.session.userId = user.id;
```

```ts
// Safer
await regenerateSession(req);
req.session.userId = user.id;
```

## Review Prompts

- Is any part of the token predictable, meaningful, or user-controlled?
- Are session IDs accepted through query strings, form fields, headers, or cookies?
- Does the app rotate IDs at every privilege boundary?
- Are old sessions invalidated after password reset, account recovery, or logout?
- Can XSS, mixed HTTP/HTTPS, or missing cookie flags expose the token?

## Source

Local summary based on the OWASP Session Management Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html`

## references/owasp-sql-injection.md

# OWASP SQL Injection Prevention

Use this reference when untrusted input reaches SQL, HQL, stored procedures, query builders, or raw ORM escape hatches.

## Review Checks

- Search for string concatenation, interpolation, template literals, and format strings in query text.
- Review dynamic `WHERE`, `ORDER BY`, `LIMIT`, table, and column fragments separately from data values.
- Verify stored procedures do not construct raw SQL internally.
- Treat escaping as a fallback layer, not the primary defense.
- Check database privileges and views so an injection cannot exceed the application's minimum needs.

## Pattern Examples

### String-built query

```ts
// Vulnerable
const sql = "SELECT * FROM users WHERE email = '" + req.query.email + "'";
const user = await db.query(sql);
```

```ts
// Safer
const user = await db.query(
  "SELECT * FROM users WHERE email = ?",
  [req.query.email]
);
```

### Dynamic sort direction

```python
# Vulnerable: identifiers usually cannot be parameter-bound.
sql = f"SELECT * FROM orders ORDER BY created_at {request.args['direction']}"
```

```python
direction = request.args.get("direction", "desc").lower()
if direction not in {"asc", "desc"}:
    raise BadRequest("invalid direction")
sql = f"SELECT * FROM orders ORDER BY created_at {direction}"
```

### Raw ORM escape hatch

```java
// Vulnerable
session.createQuery("from Inventory where productID='" + productId + "'");

// Safer
Query<Inventory> q = session.createQuery(
    "from Inventory where productID=:productId",
    Inventory.class
);
q.setParameter("productId", productId);
```

## Review Prompts

- Which values are data parameters, and which are query structure?
- Is an allowlist used for unavoidable dynamic identifiers?
- Does the application account have broader DB privileges than the path needs?
- Can an error path leak SQL details or change authorization behavior?

## Source

Local summary based on the OWASP SQL Injection Prevention Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html`

## references/owasp-xss.md

# OWASP Cross-Site Scripting Prevention

Use this reference when untrusted data reaches HTML, attributes, JavaScript, CSS, URLs, templates, or browser DOM operations.

## Review Checks

- Identify the exact output context before evaluating the encoding control.
- Prefer framework auto-escaping and safe DOM sinks, but verify escape hatches and custom rendering.
- Treat HTML, attribute, JavaScript, CSS, and URL contexts as different sinks with different encoding needs.
- Review rich-text features for dedicated sanitization rather than ad hoc filtering.
- Check that CSP is defense in depth, not the only XSS control.

## Pattern Examples

### Unsafe DOM sink

```js
// Vulnerable
preview.innerHTML = comment;
```

```js
// Safer for plain text
preview.textContent = comment;
```

### Raw template rendering

```html
<!-- Vulnerable when `bio` contains untrusted HTML -->
<div>{{{ bio }}}</div>
```

```html
<!-- Safer when the template engine escapes by default -->
<div>{{ bio }}</div>
```

### Attribute injection

```js
// Vulnerable: attacker controls both value and execution context.
node.innerHTML = `<img src="${avatarUrl}" onerror="${handler}">`;
```

```js
// Safer: hardcode the attribute name and assign a validated URL.
node.setAttribute("src", validateImageUrl(avatarUrl));
```

### Rich HTML

```js
// Vulnerable
article.innerHTML = markdownToHtml(userMarkdown);
```

```js
// Safer when HTML is intentionally allowed
article.innerHTML = htmlSanitizer.sanitize(markdownToHtml(userMarkdown));
```

## Review Prompts

- What parser context receives the value: HTML body, attribute, JS string, CSS value, or URL?
- Does the code use an unsafe sink such as `innerHTML`, `outerHTML`, or `document.write`?
- Are attributes hardcoded and non-executable?
- Is user-controlled HTML sanitized with a maintained library?
- Are JSON responses served with the correct content type instead of being rendered as HTML?

## Source

Local summary based on the OWASP Cross Site Scripting Prevention Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html`

## references/owasp-xxe.md

# OWASP XML External Entity Prevention

Use this reference when untrusted XML reaches DOM, SAX, StAX, XML schema validation, XPath, XSLT, or XML-backed import/export workflows.

## Review Checks

- Disable DTDs completely whenever possible.
- Disable external entities, external DTD loading, XInclude, and external schema fetches.
- Enable secure processing and entity expansion limits where supported.
- Verify parser defaults for the actual library and version rather than assuming safe defaults.
- Treat XXE as a path to file disclosure, SSRF, internal port scanning, and parser DoS.

## Pattern Examples

### Default Java parser

```java
// Vulnerable
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inputStream);
```

```java
// Safer
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
DocumentBuilder builder = factory.newDocumentBuilder();
```

### Unsafe Python parser

```python
# Vulnerable when parser resolves external entities.
doc = lxml.etree.fromstring(xml_bytes)
```

```python
# Safer
parser = lxml.etree.XMLParser(resolve_entities=False, load_dtd=False, no_network=True)
doc = lxml.etree.fromstring(xml_bytes, parser=parser)
```

## Review Prompts

- Does any parser allow `DOCTYPE`, external entities, or remote schema resolution?
- Can XML processing read local files or make outbound requests?
- Are parser hardening flags applied before parsing every untrusted input path?
- Are entity expansion and oversized XML inputs bounded?

## Source

Local summary based on the OWASP XML External Entity Prevention Cheat Sheet:
`https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html`

