OWASP Security · git:20260714.061716b · 2026-07-14 · sha256 d64109abc313c1c9

OWASP Security git:20260714.061716bB

Immutable. This exact content never changes and is served at /api/v1/blob/d64109abc313c1c9.

---
name: OWASP Security
description: >
  Comprehensive OWASP security knowledge for code review and vulnerability assessment.
  Use when reviewing authentication, authorization, input validation, cryptography,
  API security, session management, or any security-sensitive code. Covers OWASP Top 10:2025,
  API Security Top 10, Agentic AI Security (ASI01-ASI10), CWE Top 25, and ASVS 5.0.
allowed-tools: Bash, Read, Grep
---

# OWASP Security Knowledge

Actionable vulnerability detection and remediation for security-sensitive code review. Each section provides patterns to detect, code to fix, and rationale.

## 1. OWASP Top 10:2025

### A01:2025 Broken Access Control

Failure to enforce that users only act within their intended permissions. The most common web application vulnerability.

**Vulnerable patterns:**
```typescript
// Direct object reference without ownership check
app.get("/api/orders/:id", async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  res.json(order); // Anyone can view any order
});
```
```python
# Missing function-level access control
@app.route("/admin/users", methods=["DELETE"])
def delete_user():
    user_id = request.json["user_id"]
    db.session.delete(User.query.get(user_id))  # No role check
```

**Remediation:**
```typescript
// Enforce ownership on every data access
app.get("/api/orders/:id", authenticate, async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  if (!order || order.userId !== req.user.id) {
    return res.status(404).json({ error: "Not found" });
  }
  res.json(order);
});
```
```python
# Decorator-based role enforcement
@app.route("/admin/users", methods=["DELETE"])
@require_role("admin")
def delete_user():
    user_id = request.json["user_id"]
    db.session.delete(User.query.get(user_id))
```

**Detection signals:** Routes without auth middleware, database queries using user-supplied IDs without ownership filters, missing role checks on admin endpoints, CORS set to `*`.

### A02:2025 Cryptographic Failures

Weak or missing encryption for data in transit or at rest. Includes hardcoded secrets, weak algorithms, and improper key management.

**Vulnerable patterns:**
```typescript
// Hardcoded secret
const JWT_SECRET = "mysecretkey123";

// Weak hashing
import { createHash } from "crypto";
const hashed = createHash("md5").update(password).digest("hex");
```
```python
# Insecure randomness
import random
token = "".join(random.choice("abcdef0123456789") for _ in range(32))

# No TLS verification
requests.get("https://api.example.com", verify=False)
```

**Remediation:**
```typescript
// Environment-sourced secret with strong signing
const JWT_SECRET = process.env.JWT_SECRET;
if (!JWT_SECRET || JWT_SECRET.length < 32) {
  throw new Error("JWT_SECRET must be at least 32 characters");
}

// Strong hashing with salt
import { scrypt, randomBytes } from "crypto";
const salt = randomBytes(16).toString("hex");
scrypt(password, salt, 64, (err, derivedKey) => {
  const hashed = `${salt}:${derivedKey.toString("hex")}`;
});
```
```python
# Cryptographic randomness
import secrets
token = secrets.token_hex(32)

# Always verify TLS
requests.get("https://api.example.com", verify=True)
```

**Detection signals:** Strings matching `/secret|password|key|token/i` in source (not env), MD5/SHA1 for passwords, `Math.random()` or `random.random()` for security values, `verify=False`, `rejectUnauthorized: false`.

### A03:2025 Injection

Untrusted data sent to an interpreter as part of a command or query. Covers SQL, NoSQL, OS command, LDAP, and template injection.

**Vulnerable patterns:**
```typescript
// SQL injection via string concatenation
const query = `SELECT * FROM users WHERE id = '${req.params.id}'`;
await db.query(query);

// Command injection
const { exec } = require("child_process");
exec(`ls ${req.query.path}`);
```
```python
# NoSQL injection
users.find({"username": request.json["username"],
            "password": request.json["password"]})

# Template injection
template = f"Hello {user_input}"
return render_template_string(template)
```

**Remediation:**
```typescript
// Parameterized query
const query = "SELECT * FROM users WHERE id = $1";
await db.query(query, [req.params.id]);

// Safe subprocess with argument array
import { execFile } from "child_process";
execFile("ls", [sanitizedPath], { cwd: allowedDir });
```
```python
# Explicit field comparison, hash passwords separately
user = users.find_one({"username": str(request.json["username"])})
if user and bcrypt.checkpw(password, user["password_hash"]):
    ...

# Use template variables, never render_template_string with user input
return render_template("hello.html", name=user_input)
```

**Detection signals:** String concatenation in queries, `exec()` / `eval()` with user input, `render_template_string()`, `$where` in MongoDB queries, unsanitized `innerHTML`.

### A04:2025 Insecure Design

Flawed architecture that cannot be fixed by perfect implementation. Missing threat modeling, no abuse case analysis, no security requirements.

**Indicators:**
- No rate limiting on authentication endpoints
- Password reset via predictable tokens
- Business logic that trusts client-side validation exclusively
- No account lockout after failed attempts
- Sensitive operations without re-authentication

**Remediation approach:**
- Threat model every new feature (STRIDE or PASTA)
- Define abuse cases alongside use cases
- Enforce server-side validation for all business rules
- Design rate limiting and lockout into the architecture
- Require re-authentication for privilege changes

### A05:2025 Security Misconfiguration

Default credentials, unnecessary features enabled, overly permissive settings, missing security headers.

**Vulnerable patterns:**
```typescript
// CORS wide open
app.use(cors({ origin: "*" }));

// Debug mode in production
app.use(errorHandler({ showStack: true }));

// Default admin credentials
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || "admin";
```

**Remediation:**
```typescript
// Explicit origin allowlist
app.use(cors({
  origin: ["https://app.example.com"],
  credentials: true,
}));

// Security headers
app.use(helmet({
  contentSecurityPolicy: { directives: { defaultSrc: ["'self'"] } },
  hsts: { maxAge: 31536000, includeSubDomains: true },
}));

// No fallback credentials
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD;
if (!ADMIN_PASSWORD) throw new Error("ADMIN_PASSWORD required");
```

**Detection signals:** `origin: "*"`, missing `helmet()` or security headers, `DEBUG=true` in production configs, stack traces in error responses, directory listing enabled.

### A06:2025 Vulnerable and Outdated Components

Using libraries with known vulnerabilities or components that are no longer maintained.

**Detection:**
```bash
# Node.js
npm audit --production
npx npm-check-updates --target minor

# Python
pip-audit
safety check

# Rust
cargo audit
```

**Remediation:** Pin dependency versions, automate vulnerability scanning in CI, subscribe to security advisories, remove unused dependencies, prefer actively maintained libraries.

### A07:2025 Identification and Authentication Failures

Weak authentication mechanisms, credential stuffing exposure, session fixation, missing MFA.

**Vulnerable patterns:**
```typescript
// Weak password policy
if (password.length >= 4) { /* accept */ }

// Session ID in URL
res.redirect(`/dashboard?session=${sessionId}`);

// No brute force protection
app.post("/login", async (req, res) => {
  const user = await authenticate(req.body.email, req.body.password);
});
```

**Remediation:**
```typescript
// Strong password requirements
import { zxcvbn } from "zxcvbn";
const result = zxcvbn(password);
if (result.score < 3) {
  return { error: "Password too weak", feedback: result.feedback };
}

// Secure session handling
app.use(session({
  secret: process.env.SESSION_SECRET,
  cookie: { secure: true, httpOnly: true, sameSite: "strict", maxAge: 3600000 },
  resave: false,
  saveUninitialized: false,
}));

// Rate limiting on auth endpoints
app.use("/login", rateLimit({ windowMs: 15 * 60 * 1000, max: 5 }));
```

**Detection signals:** Password minimum length under 8, sessions in URLs, missing rate limiting on `/login` or `/register`, plaintext password storage, missing `httpOnly` or `secure` flags on session cookies.

### A08:2025 Software and Data Integrity Failures

Code and infrastructure that does not protect against integrity violations. Includes CI/CD pipeline attacks, unsigned updates, insecure deserialization.

**Vulnerable patterns:**
```typescript
// Deserializing untrusted data
const obj = JSON.parse(userInput);
await processOrder(obj); // No schema validation

// Unsigned package installation
exec("curl https://example.com/install.sh | bash");
```
```python
# Pickle deserialization from untrusted source
import pickle
data = pickle.loads(request.data)  # Remote code execution
```

**Remediation:**
```typescript
// Schema validation before processing
import { z } from "zod";
const OrderSchema = z.object({
  productId: z.string().uuid(),
  quantity: z.number().int().positive().max(100),
});
const result = OrderSchema.safeParse(JSON.parse(userInput));
if (!result.success) return res.status(400).json({ error: result.error });
await processOrder(result.data);
```
```python
# Use JSON, never pickle for untrusted data
import json
data = json.loads(request.data)
validated = OrderSchema(**data)  # Pydantic validation
```

**Detection signals:** `pickle.loads()`, `yaml.load()` without `Loader=SafeLoader`, `eval()`, unsigned artifact downloads in CI, missing subresource integrity on CDN scripts.

### A09:2025 Security Logging and Monitoring Failures

Insufficient logging of security events, no alerting, logs that leak sensitive data.

**What to log:** Authentication attempts (success and failure), authorization failures, input validation failures, server errors, privilege changes, data access to sensitive records.

**What NOT to log:** Passwords, tokens, credit card numbers, PII beyond what is needed for identification.

**Remediation:**
```typescript
// Structured security logging
function logSecurityEvent(event: {
  action: string;
  userId: string;
  ip: string;
  success: boolean;
  metadata?: Record<string, unknown>;
}) {
  logger.info({
    type: "security",
    timestamp: new Date().toISOString(),
    ...event,
  });
}

// Log auth failures
app.post("/login", async (req, res) => {
  const user = await authenticate(req.body.email, req.body.password);
  logSecurityEvent({
    action: "login",
    userId: req.body.email,
    ip: req.ip,
    success: !!user,
  });
});
```

**Detection signals:** No logging middleware, `console.log` only (no structured logging), passwords or tokens in log output, no log rotation, no alerting on repeated auth failures.

### A10:2025 Server-Side Request Forgery (SSRF)

Application fetches a URL supplied by the user without validation, allowing access to internal services.

**Vulnerable patterns:**
```typescript
// Unvalidated URL fetch
app.get("/proxy", async (req, res) => {
  const response = await fetch(req.query.url as string);
  res.send(await response.text());
});
```
```python
# SSRF via user-controlled URL
@app.route("/fetch")
def fetch_url():
    url = request.args.get("url")
    return requests.get(url).text
```

**Remediation:**
```typescript
// URL allowlist validation
const ALLOWED_HOSTS = new Set(["api.github.com", "cdn.example.com"]);

app.get("/proxy", async (req, res) => {
  const url = new URL(req.query.url as string);
  if (!ALLOWED_HOSTS.has(url.hostname)) {
    return res.status(403).json({ error: "Host not allowed" });
  }
  if (url.protocol !== "https:") {
    return res.status(403).json({ error: "HTTPS required" });
  }
  // Block private IP ranges
  const resolved = await dns.resolve4(url.hostname);
  if (isPrivateIP(resolved[0])) {
    return res.status(403).json({ error: "Internal addresses blocked" });
  }
  const response = await fetch(url.toString());
  res.send(await response.text());
});
```

**Detection signals:** `fetch()`, `axios()`, `requests.get()` with user-supplied URLs, no hostname validation, no protocol restriction, no private IP blocking.

---

## 2. OWASP API Security Top 10

### API1: Broken Object Level Authorization (BOLA)

APIs that expose object IDs and fail to verify the requesting user owns the object. The most prevalent API vulnerability.

**Detection:** Any endpoint pattern like `/api/resource/:id` where the handler fetches by ID without filtering by the authenticated user's ownership.

**Remediation:** Every data access function must include an ownership or permission filter. Never rely on obscurity of IDs.
```typescript
// Always filter by authenticated user
const order = await db.orders.findOne({
  where: { id: orderId, userId: req.user.id },
});
```

### API2: Broken Authentication

Weak or missing authentication on API endpoints. Includes missing auth on sensitive endpoints, weak token validation, and credential stuffing exposure.

**Remediation:** Use proven auth libraries (Passport.js, FastAPI Security). Validate JWTs with proper algorithm pinning (`algorithms: ["RS256"]`). Never accept `alg: none`.

### API3: Broken Object Property Level Authorization

APIs that expose more object properties than the user should see, or allow mass assignment of protected fields.

**Detection:** API responses returning full database records. Request handlers that spread user input directly into database updates.

**Remediation:**
```typescript
// Explicit response shaping
const publicFields = { id: user.id, name: user.name, email: user.email };
res.json(publicFields); // Never res.json(user)

// Explicit field allowlist on updates
const allowed = pick(req.body, ["name", "email", "avatar"]);
await db.users.update(req.user.id, allowed); // Never spread req.body
```

### API4: Unrestricted Resource Consumption

No rate limiting, pagination limits, or resource caps. Allows denial of service through legitimate API calls.

**Remediation:** Rate limit all endpoints. Cap pagination (`limit` param max 100). Set request body size limits. Timeout long-running queries. Charge or throttle expensive operations.

### API5: Broken Function Level Authorization

Regular users can access admin endpoints by guessing the URL pattern.

**Detection:** Admin routes like `/api/admin/*` without middleware enforcing admin role. Endpoints that check role in the handler body instead of middleware.

**Remediation:** Enforce authorization in middleware, not handler logic. Deny by default -- explicitly grant access per role.

### API6: Unrestricted Access to Sensitive Business Flows

Automated abuse of business features: bulk account creation, ticket scalping, coupon abuse.

**Remediation:** CAPTCHA on public-facing flows. Device fingerprinting. Velocity checks (no more than N actions per time window per user/IP).

### API7: Server Side Request Forgery

Same as A10:2025 but through API parameters. Particularly dangerous in microservice architectures where internal services trust each other.

**Remediation:** Allowlist external hosts. Block RFC 1918 addresses. Use a dedicated egress proxy for outbound requests.

### API8: Security Misconfiguration

API-specific: verbose error messages exposing stack traces, missing CORS restrictions, unnecessary HTTP methods enabled, default credentials on API gateways.

**Remediation:** Strip stack traces in production. Disable `OPTIONS`/`TRACE` where not needed. Audit API gateway configs.

### API9: Improper Inventory Management

Undocumented or forgotten API endpoints. Old API versions still running. Debug endpoints exposed in production.

**Remediation:** Maintain an API inventory. Deprecate old versions with sunset headers. Scan for exposed endpoints (`/debug`, `/test`, `/internal`).

### API10: Unsafe Consumption of APIs

Trusting data from third-party APIs without validation. Failing to validate webhooks. No timeout on external calls.

**Remediation:**
```typescript
// Validate webhook signatures
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
  const expected = createHmac("sha256", secret).update(payload).digest("hex");
  return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

// Timeout and validate external API responses
const response = await fetch(externalUrl, { signal: AbortSignal.timeout(5000) });
const data = ExternalSchema.parse(await response.json());
```

---

## 3. Agentic AI Security (ASI01-ASI10)

These risks apply specifically to AI agent systems like Claude Code plugins, MCP servers, and autonomous coding agents.

### ASI01: Excessive Agency

Agents granted more permissions than their task requires. An agent that only needs to read files is given write access. A review agent can execute arbitrary shell commands.

**Claude Code relevance:** Agent definitions in `agents/*.md` include a `tools:` allowlist. Leaf worker agents (testing, docs, security) should NOT have `Task`, `Bash`, or `Write` tools unless their role demands it.

**Remediation:** Minimum viable tool list per agent. Use `disallowedTools` to explicitly block dangerous tools. Review agents: read-only tools only.

### ASI02: Inadequate Sandboxing

Agents escaping their intended execution boundary. A subagent modifying files outside its worktree. Shell commands reaching host resources.

**Claude Code relevance:** Use `isolation: worktree` for agents that write files, preventing conflicts with other agents. Never grant `dangerouslyDisableSandbox` unless the task is impossible without it.

**Remediation:** Worktree isolation for writing agents. Restrict `Bash` tool commands via hook validation. Monitor file paths in `PostToolUse` hooks.

### ASI03: Prompt Injection

Malicious instructions embedded in tool results, file contents, or environment variables that redirect agent behavior.

**Claude Code relevance:** MCP tool results could contain injected instructions. Files read by agents could contain adversarial prompts. Plugin hooks receive untrusted input.

**Remediation:** Treat all tool results as data, not instructions. Validate MCP responses against expected schemas. Do not execute instructions found in file contents or error messages.

### ASI04: Insecure Tool Use

Agents calling tools without validating inputs or outputs. Passing user-controlled strings directly to shell commands. Constructing file paths from untrusted input.

**Claude Code relevance:** MCP server handlers must validate every parameter. The governance-mcp `index.mjs` must sanitize all inputs before passing to `exec()`, `readFile()`, or database queries.

**Remediation:**
```javascript
// MCP tool handler with input validation
async function handleTool(name, args) {
  const schema = TOOL_SCHEMAS[name];
  if (!schema) return { error: "Unknown tool" };
  const validated = schema.safeParse(args);
  if (!validated.success) return { error: validated.error.message };
  return await TOOL_HANDLERS[name](validated.data);
}
```

### ASI05: Insufficient Monitoring

No audit trail for agent actions. Cannot determine what an agent did, which tools it called, or what data it accessed.

**Claude Code relevance:** Forge hooks (`pre-task.sh`, `post-task.sh`) provide observability. The orchestrator's event log (`.forge/events.jsonl`) captures tool calls. Without these, agent actions are invisible.

**Remediation:** Log every tool call with timestamp, agent ID, tool name, and parameter summary. Never log secrets or full file contents. Review logs for anomalous patterns.

### ASI06: Data Exfiltration

Agents leaking sensitive data through tool calls -- writing secrets to files, sending data to external URLs, embedding data in commit messages.

**Claude Code relevance:** An agent with `Bash` access could `curl` data to an external server. An agent with `Write` could dump environment variables to a file.

**Remediation:** Network-restrict agent environments. Monitor outbound connections in hooks. Never pass `.env` contents through MCP tools. Use `disallowedTools` to block network tools for agents that do not need them.

### ASI07: Uncontrolled Escalation

Agents escalating their own privileges by spawning more powerful subagents, modifying their own configuration, or requesting elevated permissions.

**Claude Code relevance:** An agent with `Task` can spawn subagents with broader tool access. An agent could modify `agents/*.md` files to expand its own permissions on next invocation.

**Remediation:** Subagent tool lists must be a subset of the parent's tools. Agents should not have write access to `agents/` or `commands/` directories. Use `PostToolUse` hooks to detect self-modification.

### ASI08: Model Manipulation

Adversarial inputs designed to make the model produce incorrect or harmful output. Includes jailbreaking, token smuggling, and encoding attacks.

**Claude Code relevance:** Primarily a concern when agents process untrusted external content (web pages, user-uploaded files, third-party API responses).

**Remediation:** Do not feed raw external content directly into agent prompts. Summarize or sanitize external data before including it in context. Use structured extraction rather than free-form interpretation.

### ASI09: Supply Chain

Malicious plugins, MCP servers, or tool definitions that appear legitimate but contain backdoors.

**Claude Code relevance:** Plugins installed via marketplace, MCP servers defined in `.mcp.json`, and skills loaded from disk are all supply chain vectors. A malicious plugin could exfiltrate code or inject instructions.

**Remediation:** Audit all MCP server code before installation. Pin dependency versions in `package.json`. Review plugin source on updates. Use `npm audit` on MCP server dependencies.

### ASI10: Denial of Service

Resource exhaustion through agent loops, unbounded recursion, or deliberate overload of tool calls.

**Claude Code relevance:** An agent caught in a retry loop calling `Bash` commands repeatedly. A governance hook that triggers on every file write causing performance degradation. MCP tools with no timeout.

**Remediation:** Set iteration limits on agent loops. Add timeouts to all MCP tool handlers. Make hooks non-blocking (all Forge hooks follow this pattern). Monitor agent token consumption.

---

## 4. CWE Top 25 Most Dangerous Software Weaknesses

| Rank | CWE | Name | Detection Pattern |
|------|-----|------|-------------------|
| 1 | CWE-787 | Out-of-bounds Write | Buffer operations without bounds checking in C/C++/Rust unsafe blocks |
| 2 | CWE-79 | Cross-site Scripting (XSS) | `innerHTML`, `dangerouslySetInnerHTML`, unescaped template variables |
| 3 | CWE-89 | SQL Injection | String concatenation in SQL queries, missing parameterized queries |
| 4 | CWE-416 | Use After Free | Dangling pointers, double-free patterns in unsafe Rust or C/C++ |
| 5 | CWE-78 | OS Command Injection | `exec()`, `system()`, `child_process.exec` with user input |
| 6 | CWE-20 | Improper Input Validation | Missing schema validation on API inputs, no type checks |
| 7 | CWE-125 | Out-of-bounds Read | Array access without length checks, buffer over-reads |
| 8 | CWE-22 | Path Traversal | `../` in file paths, `path.join` with user input without `path.resolve` |
| 9 | CWE-352 | Cross-Site Request Forgery | State-changing GET requests, missing CSRF tokens on forms |
| 10 | CWE-434 | Unrestricted File Upload | File upload without type/size validation, executable uploads |
| 11 | CWE-862 | Missing Authorization | Endpoints without auth middleware, direct object references |
| 12 | CWE-476 | NULL Pointer Dereference | Missing null checks, optional chaining gaps |
| 13 | CWE-287 | Improper Authentication | Custom auth instead of proven libraries, weak token validation |
| 14 | CWE-190 | Integer Overflow | Arithmetic on user-supplied numbers without range checks |
| 15 | CWE-502 | Deserialization of Untrusted Data | `pickle.loads()`, `unserialize()`, `JSON.parse` without schema |
| 16 | CWE-77 | Command Injection | Template strings in shell commands, unsanitized arguments |
| 17 | CWE-119 | Buffer Overflow | Fixed-size buffer operations, `strcpy`/`strcat` usage |
| 18 | CWE-798 | Hard-coded Credentials | Passwords, API keys, secrets as string literals in source |
| 19 | CWE-918 | Server-Side Request Forgery | `fetch`/`requests.get` with user-controlled URLs |
| 20 | CWE-306 | Missing Authentication for Critical Function | Admin endpoints without auth check |
| 21 | CWE-362 | Race Condition | TOCTOU patterns, shared mutable state without locking |
| 22 | CWE-269 | Improper Privilege Management | setuid misuse, running as root, capability escalation |
| 23 | CWE-94 | Code Injection | `eval()`, `Function()`, `vm.runInContext` with user input |
| 24 | CWE-863 | Incorrect Authorization | Auth check present but logically flawed (wrong role, OR vs AND) |
| 25 | CWE-276 | Incorrect Default Permissions | World-writable files, `0777` permissions, public S3 buckets |

---

## 5. ASVS 5.0 Key Requirements

### V1: Architecture, Design and Threat Modeling

- Perform threat modeling for every significant feature (STRIDE minimum)
- Define trust boundaries between components
- Document data flows for sensitive information
- Identify all entry points and their authentication requirements
- Design for failure: assume any component can be compromised

### V2: Authentication

- Passwords: minimum 8 characters, no maximum less than 64, check against breach lists
- Credential storage: bcrypt/scrypt/argon2 with per-user salt, never SHA/MD5
- Session tokens: minimum 128 bits of entropy, regenerate on privilege change
- Multi-factor: require for admin accounts and sensitive operations
- Account lockout: temporary lockout after 5-10 failed attempts, with CAPTCHA

### V3: Session Management

- Session IDs: cryptographically random, never in URLs
- Cookie attributes: `Secure`, `HttpOnly`, `SameSite=Strict`, reasonable `Max-Age`
- Invalidate sessions on logout, password change, and privilege escalation
- Concurrent session limits for sensitive applications
- Idle timeout: 15-30 minutes for sensitive apps, re-auth for critical operations

### V4: Access Control

- Deny by default: explicitly grant, never explicitly deny
- Enforce at the server side, never trust client-side access control
- Principle of least privilege for every user, service account, and API key
- Log all access control failures for monitoring
- Rate limit access control checks to prevent enumeration

### V5: Validation, Sanitization, Encoding

- Validate all inputs on the server side against a strict schema
- Output-encode for the target context (HTML, URL, JavaScript, SQL, OS command)
- Use allowlists over denylists for input validation
- Structured data: validate against JSON Schema, Zod, or Pydantic
- File uploads: validate type by content (magic bytes), not extension alone

### V6: Stored Cryptography

- Symmetric encryption: AES-256-GCM (authenticated encryption)
- Key management: use a KMS, never store keys alongside encrypted data
- Password hashing: argon2id preferred, bcrypt acceptable (cost >= 12)
- Random number generation: `crypto.randomBytes` (Node.js), `secrets` (Python)
- Deprecation: MD5, SHA1, DES, RC4, ECB mode are all prohibited

### V13: API and Web Service

- All API endpoints require authentication (except health checks, public resources)
- Input validation on every endpoint with strict schemas
- Response filtering: never return internal fields, stack traces, or debug info
- Rate limiting with progressive backoff
- API versioning with deprecation timeline
- CORS: explicit origin allowlist, never wildcard with credentials

---

## 6. Forge-Specific Security Patterns

### MCP Server Security

The governance-mcp server (`servers/governance-mcp/index.mjs`) handles tool calls from Claude Code. Each handler must:

1. Validate all input parameters against expected types and ranges
2. Never pass user input to `exec()` or `execSync()` without sanitization
3. Use `path.resolve()` and verify paths stay within the project root
4. Return structured errors, never raw exception messages
5. Set timeouts on all file system and subprocess operations

```javascript
// Safe path resolution in MCP handler
function safePath(root, userPath) {
  const resolved = path.resolve(root, userPath);
  if (!resolved.startsWith(path.resolve(root))) {
    throw new Error("Path traversal blocked");
  }
  return resolved;
}
```

### Plugin Hook Security

All hooks in `hooks/scripts/` must:

- Be non-blocking (exit quickly, never hang)
- Never write secrets to stdout/stderr (output is visible to the user)
- Handle missing files and commands gracefully (no unset variable crashes)
- Use `set -euo pipefail` for bash scripts
- Never modify source files (hooks observe, they do not act)

### Rust and TypeScript Dual Stack

**Rust (forge-orchestrator):**
- Memory safety enforced by the compiler; `unsafe` blocks require justification
- File locking via `fs2` for concurrent task access
- No `unwrap()` on user input paths; use `?` propagation or explicit error handling
- Validate all MCP JSON-RPC inputs before dispatching

**TypeScript (forge-ui, governance-mcp):**
- Enable `strict: true` in tsconfig
- Prototype pollution: never use `Object.assign({}, userInput)` on untrusted data
- Use Zod or similar for runtime validation at API boundaries
- Sanitize all values rendered in HTML (React auto-escapes JSX, but `dangerouslySetInnerHTML` bypasses this)

### Claude Code Agent Security

- **Tool allowlists:** Every agent definition must specify `tools:` explicitly. Never omit it (omission grants all tools).
- **Isolation:** Agents that write files should use `isolation: worktree` to prevent cross-agent file conflicts.
- **Least privilege:** Leaf workers get read-only tools. Only orchestrators get `Task` for spawning subagents.
- **Hook validation:** `PostToolUse` hooks can detect and warn about dangerous patterns (file writes outside project, shell commands with network access).
- **Skill boundaries:** Skills with `disable-model-invocation: true` prevent accidental activation, reducing attack surface.

---

## 7. Security Review Checklist

Use this checklist when performing a security review of any codebase.

### Authentication and Session Management
- [ ] All endpoints require authentication (except explicitly public ones)
- [ ] Passwords hashed with bcrypt/scrypt/argon2 (never MD5/SHA)
- [ ] Session tokens are cryptographically random, at least 128 bits
- [ ] Session cookies have Secure, HttpOnly, SameSite attributes
- [ ] Sessions invalidated on logout and password change
- [ ] Rate limiting on authentication endpoints
- [ ] Account lockout after repeated failures

### Authorization
- [ ] Every data access checks ownership or role
- [ ] Server-side enforcement (not client-side only)
- [ ] Deny by default, grant explicitly
- [ ] Admin endpoints protected by role middleware
- [ ] No direct object references without authorization

### Input Validation
- [ ] All inputs validated server-side with strict schemas
- [ ] Parameterized queries for all database access
- [ ] No string concatenation in SQL, shell commands, or templates
- [ ] File uploads validated by content type, not extension
- [ ] Path inputs resolved and checked against allowed directories

### Cryptography
- [ ] No hardcoded secrets in source code
- [ ] Secrets loaded from environment variables or secret manager
- [ ] TLS enforced for all external communication
- [ ] Cryptographic randomness used for tokens and keys
- [ ] No deprecated algorithms (MD5, SHA1, DES, RC4)

### API Security
- [ ] Rate limiting on all endpoints
- [ ] Response bodies contain only necessary fields
- [ ] Error responses do not expose internals
- [ ] CORS configured with explicit origin allowlist
- [ ] Webhook signatures verified

### Logging and Monitoring
- [ ] Authentication events logged (success and failure)
- [ ] Authorization failures logged
- [ ] No secrets, tokens, or passwords in logs
- [ ] Structured logging format for automated analysis
- [ ] Alerting configured for anomalous patterns

### Dependencies
- [ ] `npm audit` / `pip-audit` / `cargo audit` clean
- [ ] No known vulnerable dependencies in production
- [ ] Dependency versions pinned
- [ ] Unused dependencies removed

### Agent and Plugin Security (Forge-specific)
- [ ] Agent tool lists follow least privilege
- [ ] MCP handlers validate all inputs
- [ ] Hooks are non-blocking and do not leak secrets
- [ ] No `eval()` or `exec()` with unsanitized input in MCP server
- [ ] Subagent tool lists are subsets of parent agent tools

---

## 8. False Positive Filters

When reviewing security findings, skip these low-signal patterns to avoid noise:

### Skip: ReDoS (Regular Expression Denial of Service)
Regex-based DoS findings are low-confidence in most application contexts. Only flag if the regex processes untrusted input in a hot path with no timeout. Standard form validation regexes are not worth flagging.

### Skip: Info Disclosure in Error Messages (Development Mode)
Error messages containing stack traces or internal paths are expected in development. Only flag if the production error handler exposes internals. Check for `NODE_ENV=production` or equivalent guards.

### Skip: Missing Rate Limiting on Internal Endpoints
Endpoints only accessible within a VPC or behind an API gateway with its own rate limiting do not need per-endpoint rate limits. Flag only if the endpoint is publicly accessible.

### Skip: Test File Findings
Security issues in test files (`__tests__/`, `tests/`, `*.test.*`, `*.spec.*`) are not production vulnerabilities. Hardcoded test credentials, weak crypto in test helpers, and permissive CORS in test servers are expected and acceptable.

### Skip: Documentation Examples
Code samples in `README.md`, `docs/`, or JSDoc comments are illustrative. Do not flag them as vulnerabilities unless they are copy-pasteable production code with dangerous defaults.

### Skip: Type-Only Issues
Missing TypeScript types, `any` usage, or loose type assertions are code quality issues, not security vulnerabilities. Only flag `any` if it bypasses runtime validation at a trust boundary.

### Contextual Judgment
When in doubt, ask: "Can an attacker exploit this in production with realistic access?" If the answer requires admin access, physical access, or modifying the source code -- it is not a security finding.