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.
Installs into .claude/skills of the current project.
Are you the author of Owasp Security?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/nxtg-ai-owasp-security)
---
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.
---
# 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.