git:20260714.061716b to git:20260714.4fd0952

120 added, 761 removed. Audit B to B.

---
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 vulnerability detection + remediation knowledge for security code review.
+ Use when reviewing or hardening authentication, authorization, input validation,
+ cryptography, API endpoints, session management, deserialization, SSRF, or file
+ uploads — or auditing a Claude Code plugin / MCP server / agent for excessive
+ agency, prompt injection, or supply-chain risk. Covers OWASP Top 10:2025,
+ API Security Top 10, Agentic AI Security (ASI01–ASI10), CWE Top 25, ASVS 5.0.
+ when_to_use: >
+ "security audit before we ship", "review this auth/JWT/login code", "is this
+ SQL injectable", "check for secrets / hardcoded credentials", "is this endpoint
+ authorized", "SSRF / open redirect", "review the MCP server / agent tool
+ permissions", "OWASP Top 10 check", "harden this API".
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).
+ Detection-first reference for security-sensitive code review. The tables below are the **triage layer** — one detection signal per category, kept inline so this skill is useful the moment it preloads into the security agent. When a signal fires, open the matching `reference/*.md` for the vulnerable→fixed code.
- ### API7: Server Side Request Forgery
+ ## How to use this skill
- Same as A10:2025 but through API parameters. Particularly dangerous in microservice architectures where internal services trust each other.
+ 1. Scan the diff/codebase against the **detection signals** below (grep the patterns).
+ 2. On a hit, open the linked reference for the remediation pattern.
+ 3. Before reporting, run the **Security Review Checklist** (§ below).
+ 4. Filter results through **False Positive Filters** — do not report noise.
+ 5. For Forge's own plugin/MCP/agent code, apply **Forge-Specific Patterns**.
- **Remediation:** Allowlist external hosts. Block RFC 1918 addresses. Use a dedicated egress proxy for outbound requests.
+ ## OWASP Top 10:2025 — detection signals
- ### API8: Security Misconfiguration
+ Full vulnerable→fixed code: [reference/owasp-top10.md](reference/owasp-top10.md).
- API-specific: verbose error messages exposing stack traces, missing CORS restrictions, unnecessary HTTP methods enabled, default credentials on API gateways.
+ | ID | Category | Grep for |
+ |----|----------|----------|
+ | A01 | Broken Access Control | routes without auth middleware; queries using user IDs with no ownership filter; missing role checks; `origin: "*"` |
+ | A02 | Cryptographic Failures | `secret\|password\|key\|token` literals in source (not env); MD5/SHA1 on passwords; `Math.random()`/`random.random()` for security; `verify=False`; `rejectUnauthorized: false` |
+ | A03 | Injection | string concatenation in queries; `exec()`/`eval()` with user input; `render_template_string()`; `$where` in Mongo; unsanitized `innerHTML` |
+ | A04 | Insecure Design | no rate limit on auth; predictable reset tokens; client-only validation; no lockout; no re-auth on privilege change |
+ | A05 | Security Misconfiguration | `origin: "*"`; missing `helmet()`/headers; `DEBUG=true` in prod; stack traces in responses; directory listing |
+ | A06 | Vulnerable Components | run `npm audit --production` / `pip-audit` / `cargo audit`; unpinned or unmaintained deps |
+ | A07 | Auth Failures | password min length < 8; sessions in URLs; no rate limit on `/login`/`/register`; plaintext passwords; missing `httpOnly`/`secure` cookie flags |
+ | A08 | Integrity Failures | `pickle.loads()`; `yaml.load()` without `SafeLoader`; `eval()`; `curl … \| bash`; missing CDN subresource integrity |
+ | A09 | Logging Failures | no logging middleware; `console.log`-only; secrets/tokens in log output; no alerting on repeated auth failures |
+ | A10 | SSRF | `fetch()`/`axios()`/`requests.get()` with user-supplied URL; no hostname allowlist; no protocol restriction; no private-IP block |
- **Remediation:** Strip stack traces in production. Disable `OPTIONS`/`TRACE` where not needed. Audit API gateway configs.
+ ## API Security Top 10 — detection signals
- ### API9: Improper Inventory Management
+ Full remediation: [reference/api-security.md](reference/api-security.md).
- Undocumented or forgotten API endpoints. Old API versions still running. Debug endpoints exposed in production.
+ | ID | Category | Grep for |
+ |----|----------|----------|
+ | API1 | Broken Object Level Auth (BOLA) | `/resource/:id` handler fetching by ID without `userId`/ownership filter |
+ | API2 | Broken Authentication | missing auth on sensitive endpoints; `alg: none`; no JWT algorithm pinning |
+ | API3 | Broken Object Property Level Auth | `res.json(user)` (full record); `req.body` spread into DB update (mass assignment) |
+ | API4 | Unrestricted Resource Consumption | no rate limit; uncapped `limit` param; no body-size limit; no query timeout |
+ | API5 | Broken Function Level Auth | `/api/admin/*` without role middleware; role checked in handler body |
+ | API6 | Sensitive Business Flow abuse | no CAPTCHA/velocity check on signup, checkout, coupon flows |
+ | API7 | SSRF (API params) | user URL reaching internal microservices; no RFC 1918 block |
+ | API8 | Security Misconfiguration | stack traces in prod; `OPTIONS`/`TRACE` enabled; default gateway creds |
+ | API9 | Improper Inventory | `/debug`, `/test`, `/internal`, old API versions still live |
+ | API10 | Unsafe API Consumption | unvalidated third-party responses; unverified webhooks; no external-call timeout |
- **Remediation:** Maintain an API inventory. Deprecate old versions with sunset headers. Scan for exposed endpoints (`/debug`, `/test`, `/internal`).
+ ## Agentic AI Security (ASI01–ASI10)
- ### API10: Unsafe Consumption of APIs
+ Applies to Claude Code plugins, MCP servers, and autonomous agents — including this repo. Full per-risk detail with Forge relevance: [reference/agentic-ai.md](reference/agentic-ai.md).
- Trusting data from third-party APIs without validation. Failing to validate webhooks. No timeout on external calls.
+ | ID | Risk | Forge check |
+ |----|------|-------------|
+ | ASI01 | Excessive Agency | agent `tools:` list wider than the role needs (leaf worker with `Task`/`Bash`/`Write`) |
+ | ASI02 | Inadequate Sandboxing | file-writing agent without `isolation: worktree`; `dangerouslyDisableSandbox` |
+ | ASI03 | Prompt Injection | tool results / file contents / hook input treated as instructions |
+ | ASI04 | Insecure Tool Use | MCP handler using a parameter without schema validation |
+ | ASI05 | Insufficient Monitoring | no event log / hook trail for agent tool calls |
+ | ASI06 | Data Exfiltration | `Bash` agent able to `curl` out; `.env` piped through an MCP tool |
+ | ASI07 | Uncontrolled Escalation | agent with write access to `agents/`/`commands/`; subagent tools ⊄ parent tools |
+ | ASI08 | Model Manipulation | raw external content fed straight into an agent prompt |
+ | ASI09 | Supply Chain | unaudited MCP server / marketplace plugin; unpinned MCP deps |
+ | ASI10 | Denial of Service | agent retry loop; MCP handler with no timeout; blocking hook |
- **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));
- }
+ ## CWE Top 25 & ASVS 5.0
- // Timeout and validate external API responses
- const response = await fetch(externalUrl, { signal: AbortSignal.timeout(5000) });
- const data = ExternalSchema.parse(await response.json());
- ```
+ Full CWE-25 detection table and ASVS V1–V13 requirements: [reference/cwe-asvs.md](reference/cwe-asvs.md). Use CWE for classifying a finding by ID and ASVS for the "what does secure look like" bar during design review.
---
- ## 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.
+ ## Forge-Specific Security Patterns
- ### ASI09: Supply Chain
+ These target Forge's own code. Grounded in the real plugin source.
- Malicious plugins, MCP servers, or tool definitions that appear legitimate but contain backdoors.
+ ### governance-mcp (`servers/governance-mcp/tools.mjs`)
- **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.
+ The MCP tools call `execSync` (single helper, line ~29, `timeout: 15000`) to run **fixed governance commands** (`git status`, `npm audit`, test runners) — no user- or tool-supplied value currently reaches the shell. Keep it that way:
- **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.
+ 1. **Never interpolate a user- or tool-supplied value into those `execSync` calls.** The current safety is that the command strings are constants; a future edit that string-builds a command from a tool argument reintroduces CWE-78.
+ 2. Validate every tool parameter against expected type/range before use.
+ 3. If a handler ever accepts a path, resolve it and confirm it stays under the project root (forward guidance — not yet in source):
+ ```javascript
+ function safePath(root, userPath) {
+ const resolved = path.resolve(root, userPath);
+ if (!resolved.startsWith(path.resolve(root))) throw new Error("Path traversal blocked");
+ return resolved;
+ }
+ ```
+ 4. Return structured errors, never raw exception messages.
+ 5. Keep the `timeout` on every `execSync`/file operation.
- ### ASI10: Denial of Service
+ ### Plugin hooks (`hooks/scripts/`)
- Resource exhaustion through agent loops, unbounded recursion, or deliberate overload of tool calls.
+ The four PreToolUse guards (`security-command-guard`, `security-secret-shield`, `security-injection-guard`, `security-sql-guard`) are **BLOCKING** (`exit 2` denies the tool call). `security-semgrep-scan` (PostToolUse) is **advisory** (`exit 0`). When editing or adding a hook:
- **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.
+ - Non-blocking by default; only the four named PreToolUse guards may `exit 2`, and only on a confirmed dangerous pattern.
+ - Never write secrets to stdout/stderr (hook output is user-visible).
+ - Handle missing files/commands gracefully; use `set -euo pipefail`.
+ - Hooks observe — they never modify source files.
- **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.
+ ### Dual stack
- ---
+ **Rust (forge-orchestrator):** compiler-enforced memory safety; `unsafe` blocks need justification; no `unwrap()` on user paths (use `?`); validate all MCP JSON-RPC inputs before dispatch.
+ **TypeScript (forge-ui, governance-mcp):** `strict: true`; never `Object.assign({}, userInput)` on untrusted data (prototype pollution); Zod at API boundaries; JSX auto-escapes but `dangerouslySetInnerHTML` bypasses it.
- ## 4. CWE Top 25 Most Dangerous Software Weaknesses
+ ### Claude Code agents
- | 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 |
+ Every agent must specify `tools:` explicitly (omission grants all tools). File-writing agents use `isolation: worktree`. Leaf workers get read-only tools; only orchestrators get `Task`. Subagent tool lists must be a subset of the parent's.
---
- ## 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
+ ## Security Review Checklist
- - 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
+ Run before reporting findings.
- ### V4: Access Control
+ **Auth & Session:** all endpoints require auth (except explicitly public) · passwords bcrypt/scrypt/argon2 (never MD5/SHA) · session tokens ≥128 bits random · cookies `Secure`+`HttpOnly`+`SameSite` · sessions invalidated on logout/password-change · rate limiting on auth · account lockout.
- - 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
+ **Authorization:** every data access checks ownership or role · server-side enforcement · deny by default · admin endpoints behind role middleware · no unauthorized direct object references.
- ### V5: Validation, Sanitization, Encoding
+ **Input Validation:** all inputs validated server-side with strict schemas · parameterized queries everywhere · no string concat in SQL/shell/templates · file uploads validated by content type · path inputs resolved + checked against allowed dirs.
- - 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
+ **Cryptography:** no hardcoded secrets · secrets from env/secret-manager · TLS enforced · cryptographic randomness for tokens/keys · no MD5/SHA1/DES/RC4.
- ### V6: Stored Cryptography
+ **API:** rate limiting on all endpoints · responses contain only necessary fields · errors do not expose internals · CORS explicit origin allowlist · webhook signatures verified.
- - 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
+ **Logging:** auth events logged (success + failure) · authorization failures logged · no secrets/tokens/passwords in logs · structured format · alerting on anomalies.
- ### V13: API and Web Service
+ **Dependencies:** `npm audit`/`pip-audit`/`cargo audit` clean · no known-vulnerable prod deps · versions pinned · unused deps removed.
- - 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
+ **Agent & Plugin (Forge):** agent tool lists follow least privilege · MCP handlers validate all inputs · hooks non-blocking + no secret leaks · no `eval()`/`exec()` with unsanitized input in MCP · subagent tools ⊆ parent tools.
---
- ## 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
+ ## False Positive Filters
- **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)
+ Skip these low-signal patterns to avoid noise:
- ### Claude Code Agent Security
+ - **ReDoS:** flag only if a regex processes untrusted input in a hot path with no timeout. Standard form-validation regexes are not worth flagging.
+ - **Info disclosure in dev-mode errors:** stack traces are expected in development. Flag only if the **production** error handler exposes internals (check `NODE_ENV=production` guards).
+ - **Rate limiting on internal endpoints:** endpoints behind a VPC / gateway with its own rate limiting are fine. Flag only if publicly accessible.
+ - **Test files:** issues in `__tests__/`, `tests/`, `*.test.*`, `*.spec.*` (hardcoded test creds, weak test-helper crypto, permissive test-server CORS) are acceptable.
+ - **Documentation examples:** code in `README.md`, `docs/`, JSDoc is illustrative — not a vuln unless it is copy-pasteable production code with dangerous defaults.
+ - **Type-only issues:** missing types / `any` are quality, not security — flag `any` only when it bypasses runtime validation at a trust boundary.
- - **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.
+ **Contextual judgment:** ask "Can an attacker exploit this in production with realistic access?" If exploitation requires admin access, physical access, or editing the source — it is not a security finding.
---
- ## 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
+ ## Gotchas
- ### Dependencies
- - [ ] `npm audit` / `pip-audit` / `cargo audit` clean
- - [ ] No known vulnerable dependencies in production
- - [ ] Dependency versions pinned
- - [ ] Unused dependencies removed
+ Real failure modes specific to reviewing in this plugin's environment:
- ### 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
+ - **A clean Semgrep hook run ≠ clean code.** `security-semgrep-scan.sh` is PostToolUse and advisory (`exit 0`) — the write already landed and the scan never blocks it. The reviewer, not the hook, is the gate. Do not treat "no Semgrep output" as "no vulnerability."
+ - **The PreToolUse guards are pattern-based, not semantic.** `security-command-guard` matches literals like `rm -rf /` and `chmod 777`; `security-sql-guard` matches string-concat-with-SQL-keyword. Obfuscated or logically-equivalent forms slip through. A passing guard is not proof of safety — still review by hand.
+ - **governance-mcp is safe today by construction, not by validation.** Its `execSync` calls run constant command strings; there is no input-sanitization layer. A refactor that builds a command from a tool argument silently converts a safe call into CWE-78 with no test catching it. Treat any new interpolation into `execSync` as a finding.
+ - **`res.json(record)` is the most common Forge-adjacent BOLA/API3 miss.** Returning a full DB row leaks fields the client should not see AND enables mass-assignment on the write path. Always look for explicit field shaping.
+ - **Agent `tools:` omission = all tools.** An agent `.md` with no `tools:` frontmatter is not "no tools" — it inherits everything. Missing `tools:` on a leaf worker is an ASI01 finding, not a default.
---
- ## 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.
+ ## Additional resources
- ### 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.
+ - OWASP Top 10:2025 vulnerable→fixed code — [reference/owasp-top10.md](reference/owasp-top10.md)
+ - API Security Top 10 remediation — [reference/api-security.md](reference/api-security.md)
+ - Agentic AI Security (ASI01–ASI10) with Forge relevance — [reference/agentic-ai.md](reference/agentic-ai.md)
+ - CWE Top 25 table + ASVS 5.0 requirements — [reference/cwe-asvs.md](reference/cwe-asvs.md)