OWASP Security · git:20260715.857b62e · 2026-07-15 · sha256 b3a3f32e42af3cef
OWASP Security git:20260715.857b62eC
Immutable. This exact content never changes and is served at /api/v1/blob/b3a3f32e42af3cef.
---
name: OWASP Security
description: >
OWASP vulnerability detection + remediation for security code review, PLUS the
Forge plugin's own security guards (why a "SECURITY BLOCK" / exit-2 fired and the
correct fix). Use when reviewing or hardening authentication, authorization, input
validation, cryptography, API endpoints, session management, deserialization, SSRF,
or file uploads; when auditing a Claude Code plugin / MCP server / agent for
excessive agency, prompt injection, or supply-chain risk; or when a Bash/Write/Edit
was blocked by a Forge guard (rm -rf, chmod 777, curl|sh, force-push, eval(),
os.system, shell=True, string-concat SQL, reading .env/*.pem/*.key). Covers OWASP
Top 10:2025, API Security Top 10, Agentic AI (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", "SECURITY BLOCK / my
command/write got blocked / exit 2 / hook denied", "how do I run rm -rf / chmod /
force push", "eval blocked", "cannot read .env", "Semgrep finding", "is this safe
to write", "what does Forge scan for".
allowed-tools: Bash, Read, Grep
---
# OWASP Security Knowledge
Detection-first reference for security-sensitive code review, and the operating
guide to the Forge plugin's own security guards. 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.
This skill covers guidance for **any** stack a Forge user builds in (TypeScript/JS,
Python, Rust, Go, …). Examples are illustrative, not tied to any one codebase.
## How to use this skill
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. If a write/command was **blocked** by a Forge guard, jump to **Forge security
controls** for the reason + correct fix.
## OWASP Top 10:2025 — detection signals
Full vulnerable→fixed code: [reference/owasp-top10.md](reference/owasp-top10.md).
| 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 |
## API Security Top 10 — detection signals
Full remediation: [reference/api-security.md](reference/api-security.md).
| 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 |
## Agentic AI Security (ASI01–ASI10)
Applies to Claude Code plugins, MCP servers, and autonomous agents. Full per-risk
detail: [reference/agentic-ai.md](reference/agentic-ai.md).
| ID | Risk | What to 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 / audit 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 |
## CWE Top 25 & ASVS 5.0
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.
---
## Forge security controls (PREVENT → DETECT → ASSESS)
The Forge plugin ships a real three-phase security system that runs **in the user's
own project** whenever the plugin is installed. Know it well: it is both a safety net
you rely on and a set of guards that will block you.
| Phase | Mechanism | Blocking? | Where |
|-------|-----------|-----------|-------|
| **PREVENT** | 4 PreToolUse hooks | **YES — exit 2 denies the call** | `hooks/scripts/security-*-guard.sh`, `security-secret-shield.sh` |
| **DETECT** | Semgrep PostToolUse scan | No — advisory only | `hooks/scripts/security-semgrep-scan.sh` |
| **ASSESS** | `security` agent + this skill | No — deep LLM review | `agents/security.md` |
### PREVENT — the four guards (why you got blocked, and the fix)
When a write or command exits 2 the hook prints `SECURITY BLOCK: <reason>` to stderr.
**The fix is always the safe alternative — never a bypass.** These guards have no
environment-variable escape hatch. Full remediation tables (every blocked pattern +
the corrected form) and the exact coverage boundaries are in
[reference/forge-controls.md](reference/forge-controls.md). The headline fixes:
- **Command Guard** (`Bash`) — blocks `rm -rf /`, `chmod 777`, `curl … | sh`, fork
bombs, `git push --force … main/master`, `git reset --hard`. Do instead: scope the
path (`rm -rf /tmp/build`), `chmod 644`/`755`, download→review→run,
`--force-with-lease`, `git stash` before reset.
- **Secret Shield** (`Read`/`Write`/`Edit`/`NotebookEdit`) — blocks by basename:
`.env` variants, `*.pem *.key *.p12 *.pfx *.jks`, `id_rsa`/`id_ed25519`,
`*credentials*`, `kubeconfig`, anything under `*/.ssh/ */.gnupg/ */.aws/`. It fires
on **Read** too. Work with `.env.example`, never `.env`.
- **Injection Guard** (`Write`/`Edit`/`NotebookEdit`) — blocks `eval(` /
`new Function(` (JS/TS), `os.system(` / `subprocess(… shell=True)` (Python),
`child_process.exec(` (Node), PHP `system/exec/passthru/shell_exec`. Use
`execFile()`/`spawn()`, `subprocess.run([...], shell=False)`.
- **SQL Guard** (`Write`/`Edit`/`NotebookEdit`) — blocks user-interpolated SQL
(CWE-89): template literals `` `SELECT … ${x}` ``, `"SELECT …" + x`, Python
f-strings `f"SELECT … {x}"`. Use parameterized queries (examples below).
### Worked example — a blocked write
```
Write servers/api/orders.js →
SECURITY BLOCK: SQL injection patterns detected in orders.js
- Template literal SQL with interpolation detected (CWE-89)
```
**Diagnosis:** the SQL guard saw `` `SELECT * FROM orders WHERE id = ${req.params.id}` ``.
**Fix — resubmit the Write with a parameterized query, and add the ownership filter
the guard cannot see:**
```js
const order = await db.query(
'SELECT * FROM orders WHERE id = $1 AND user_id = $2',
[req.params.id, req.user.id] // + ownership predicate (BOLA / A01)
);
```
The write now passes the guard, and the ownership predicate closes the access-control
gap. Parameterized forms in other stacks:
```python
cursor.execute('SELECT * FROM orders WHERE id = %s AND user_id = %s', (order_id, user_id))
```
```rust
sqlx::query!("SELECT * FROM orders WHERE id = $1 AND user_id = $2", order_id, user_id)
```
```go
db.Query("SELECT * FROM orders WHERE id = $1 AND user_id = $2", orderID, userID)
```
### DETECT — Semgrep (advisory)
After every source-file Write/Edit, `security-semgrep-scan.sh` runs
`semgrep scan --config auto` on that one file and prints up to 5 findings. It **never
blocks**. If Semgrep is not installed it prints a hint once and no-ops — so silence is
not a clean bill. Run a full scan yourself when hardening:
```bash
semgrep scan --config auto --config "p/owasp-top-ten" --config "p/secrets" .
npm audit --production # or: pip-audit / cargo audit
```
---
## Secure-coding quick reference (any stack)
- **Input:** validate server-side against a strict schema (Zod / Pydantic / serde /
`encoding/json` + validation); allowlist over denylist; validate uploads by magic
bytes, not extension.
- **AuthN:** hash passwords with argon2id/bcrypt (cost ≥ 12) — never MD5/SHA; MFA for
admin; rate-limit + lockout on `/login`.
- **AuthZ:** deny by default; filter every data read by owner/role in middleware, not
the handler body; never trust client-side checks.
- **Crypto:** secrets from env/KMS, never literals; CSPRNG (`crypto.randomBytes`,
Python `secrets`, Go `crypto/rand`, Rust `rand::rngs::OsRng`) — never `Math.random`;
TLS verification on (`verify=True`, `rejectUnauthorized: true`).
- **Secrets:** `.env` in `.gitignore`; ship `.env.example`; never log tokens.
- **APIs:** shape responses (allowlist fields, never `res.json(user)`); allowlist
update fields (no `spread req.body` / mass-assignment); allowlist SSRF hosts + block
RFC-1918.
### Language-specific pitfalls
- **TypeScript / JS:** prototype pollution — never merge untrusted input into objects
(`Object.assign({}, userInput)`); `dangerouslySetInnerHTML` bypasses JSX escaping;
enable `strict: true`; validate at every trust boundary with Zod.
- **Python:** `pickle.loads` / `yaml.load` (without `SafeLoader`) are RCE on untrusted
data; `subprocess(shell=True)` with interpolation is command injection; validate with
Pydantic; use `secrets`, not `random`, for tokens.
- **Rust:** minimize `unsafe` and justify every block; avoid `unwrap()`/`expect()` on
external input (propagate with `?`); validate deserialized (serde) input against
expected ranges; memory safety is compiler-enforced but logic/authz bugs are not.
- **Go:** check **every** returned `error` (a dropped `err` hides auth/validation
failures); use `html/template` (context-aware auto-escaping), not `text/template`,
for HTML; never `exec.Command("sh", "-c", userInput)`.
### Claude Code agents / MCP servers (if the reviewed project builds them)
- Every agent must declare `tools:` explicitly — **omission grants all tools**, so a
missing `tools:` on a leaf worker is an ASI01 finding, not a safe default.
- 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.
- MCP tool handlers validate every parameter against a schema before use; never
interpolate a tool-supplied value into a shell command (CWE-78); add a timeout to
every handler; return structured errors, never raw exception text.
---
## Security Review Checklist
Run before reporting findings.
**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.
**Authorization:** every data access checks ownership or role · server-side enforcement · deny by default · admin endpoints behind role middleware · no unauthorized direct object references.
**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.
**Cryptography:** no hardcoded secrets · secrets from env/secret-manager · TLS enforced · cryptographic randomness for tokens/keys · no MD5/SHA1/DES/RC4.
**API:** rate limiting on all endpoints · responses contain only necessary fields · errors do not expose internals · CORS explicit origin allowlist · webhook signatures verified.
**Logging:** auth events logged (success + failure) · authorization failures logged · no secrets/tokens/passwords in logs · structured format · alerting on anomalies.
**Dependencies:** `npm audit`/`pip-audit`/`cargo audit` clean · no known-vulnerable prod deps · versions pinned · unused deps removed.
**Agent & Plugin (if applicable):** 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.
---
## False Positive Filters
Skip these low-signal patterns to avoid noise:
- **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` / equivalent 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/`, doc-comments 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.
**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.
---
## Gotchas
Real failure modes when reviewing with these controls in play. Full coverage-boundary
list: [reference/forge-controls.md](reference/forge-controls.md#coverage-boundaries).
- **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. "No Semgrep output" may just mean Semgrep is
uninstalled.
- **The PreToolUse guards are pattern-based, not semantic.** They match literals
(`rm -rf /`, `chmod 777`, string-concat-with-SQL-keyword). Obfuscated or
logically-equivalent forms slip through. A passing guard is not proof of safety.
- **Guards read only the changed slice** — `.tool_input.content` (Write) or
`.tool_input.new_string` (Edit). A dangerous line already in the file is invisible
until you next edit it.
- **`.sh`/`.bash` files are exempt** from the injection and SQL guards (shell scripts
legitimately use `eval`/`exec`), and **`MultiEdit` is not matched by any guard**
(suspected `hooks.json` coverage gap — verify against `hooks/hooks.json` before
relying on it). Guard silence on those says nothing about safety.
- **`res.json(record)` is the most common 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
inherits everything — an ASI01 finding on a leaf worker, not a safe default.
---
## Additional resources
- 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) — [reference/agentic-ai.md](reference/agentic-ai.md)
- CWE Top 25 table + ASVS 5.0 requirements — [reference/cwe-asvs.md](reference/cwe-asvs.md)
- Forge guards: full blocked-write remediation + coverage boundaries — [reference/forge-controls.md](reference/forge-controls.md)
- Full audit workflow (recon → SAST → secrets → OWASP → API → agentic → test-integrity, with severity + finding format): the **`security`** agent (`agents/security.md`), which preloads this skill.