From 072351a2e8e2bc780e100865e237a1708a1b87aa Mon Sep 17 00:00:00 2001 From: Bruno Azoulay Date: Tue, 10 Nov 2026 04:48:17 +0100 Subject: [PATCH 1/2] feat(security): port claude-plugins security plugin refresh (v1.39.47) - New skill: agentic-security. - Refreshed: auth-audit, cve-research, dependency-audit, security-headers, security-scan skills (with new references), security-expert agent, scan command, apex-workflow and security-rules rules, README. - Cursor adaptations: scan command runs `npx -y @fusengine/harness scan `; agent model grok-4.6; Agent -> Task; no SendMessage/Edit; Allowed-tools block. - mcp.json.bak not ported. --- .../plugins/fuse-security/README.md | 71 +++--- .../fuse-security/agents/security-expert.md | 110 +++++---- .../plugins/fuse-security/commands/scan.md | 71 +++--- .../fuse-security/rules/apex-workflow.md | 37 ++- .../fuse-security/rules/security-rules.md | 78 ++++--- .../skills/agentic-security/SKILL.md | 75 +++++++ .../agentic-security/references/ci-agents.md | 48 ++++ .../references/hooks-plugins.md | 59 +++++ .../agentic-security/references/mcp-trust.md | 57 +++++ .../references/permissions.md | 56 +++++ .../references/prompt-injection.md | 50 +++++ .../agentic-security/references/secrets.md | 53 +++++ .../references/standards-map.md | 59 +++++ .../references/templates/audit-checklist.md | 58 +++++ .../references/templates/audit-report.md | 70 ++++++ .../references/trust-boundary.md | 73 ++++++ .../references/verification.md | 67 ++++++ .../fuse-security/skills/auth-audit/SKILL.md | 83 +++---- .../auth-audit/references/auth-patterns.md | 179 ++++++++++----- .../references/authorization-patterns.md | 123 ++++++++++ .../references/templates/auth-checklist.md | 126 ++++++----- .../skills/cve-research/SKILL.md | 90 ++++---- .../cve-research/references/cve-apis.md | 92 +++++--- .../references/severity-and-reachability.md | 61 +++++ .../references/templates/cve-query.md | 91 ++++---- .../skills/dependency-audit/SKILL.md | 106 +++++---- .../references/audit-commands-systems.md | 102 +++++++++ .../references/audit-commands.md | 144 ++++++------ .../references/ci-github-actions.md | 82 +++++++ .../references/supply-chain.md | 85 +++++++ .../references/templates/audit-report.md | 88 +++++--- .../skills/security-headers/SKILL.md | 82 +++---- .../references/headers-reference.md | 115 +++++++--- .../references/live-verification.md | 73 ++++++ .../references/templates/headers-config.md | 171 +++++++++++--- .../skills/security-scan/SKILL.md | 131 ++++++----- .../references/graphql-security.md | 39 ++-- .../security-scan/references/owasp-top10.md | 58 ++++- .../security-scan/references/sast-tools.md | 65 ++++++ .../references/scan-patterns-extra.md | 148 ++++++------ .../references/scan-patterns-other.md | 77 +++++++ .../references/scan-patterns-php.md | 89 ++++++++ .../security-scan/references/scan-patterns.md | 211 +++++++++--------- .../references/secrets-patterns.md | 127 +++++++++++ .../references/templates/scan-report.md | 115 +++++++--- .../skills/security-scan/references/triage.md | 106 +++++++++ 46 files changed, 3177 insertions(+), 974 deletions(-) create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/SKILL.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/ci-agents.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/hooks-plugins.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/mcp-trust.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/permissions.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/prompt-injection.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/secrets.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/standards-map.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/templates/audit-checklist.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/templates/audit-report.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/trust-boundary.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/agentic-security/references/verification.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/auth-audit/references/authorization-patterns.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/cve-research/references/severity-and-reachability.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/audit-commands-systems.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/ci-github-actions.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/supply-chain.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/security-headers/references/live-verification.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/security-scan/references/sast-tools.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/security-scan/references/scan-patterns-other.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/security-scan/references/scan-patterns-php.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/security-scan/references/secrets-patterns.md create mode 100644 .cursor-plugin/plugins/fuse-security/skills/security-scan/references/triage.md diff --git a/.cursor-plugin/plugins/fuse-security/README.md b/.cursor-plugin/plugins/fuse-security/README.md index 8e095c0..44f8a89 100644 --- a/.cursor-plugin/plugins/fuse-security/README.md +++ b/.cursor-plugin/plugins/fuse-security/README.md @@ -1,9 +1,10 @@ # fuse-security (Cursor Plugin) Security vulnerability detection and remediation: OWASP Top 10, SAST pattern scanning, CVE -research, dependency audit, secrets detection, security headers, auth hardening. +research, dependency audit, secrets detection, security headers, auth hardening, and review of +AI-agent configuration (`agentic-security`). -Ported from the Claude Code plugin `fuse-security` v1.0.16. The plugin name is deliberately +Ported from the Claude Code plugin `fuse-security` v1.0.22 (claude-plugins tag `v1.39.47`). The plugin name is deliberately identical across both ecosystems so cross-plugin references (`fuse-security:`) keep resolving. @@ -12,13 +13,14 @@ resolving. | Component | Count | Cursor discovery | | :-- | :-- | :-- | | Agents (subagents) | 1 | `agents/*.md` | -| Skills | 5 | `skills//SKILL.md` | +| Skills | 6 | `skills//SKILL.md` | | Commands | 1 | `commands/*.md` | | Hooks | 3 events | `hooks/hooks.json` | | Rules | 2 | `rules/*.md` — discovered candidates; plain-`.md` activation runtime-unverified | -`rules/apex-workflow.md` and `rules/security-rules.md` are ported verbatim at the same relative -path (R20c). Cursor's plugin reference includes `rules/` in default discovery and accepts `.md` +`rules/apex-workflow.md` and `rules/security-rules.md` are ported at the same relative path +(R20c); `security-rules.md` is verbatim, `apex-workflow.md` differs only by the harness scan +command (see Commands below). Cursor's plugin reference includes `rules/` in default discovery and accepts `.md` candidates. The Rules format documentation focuses on `.mdc` files with rule frontmatter, so native activation of these plain source-identical `.md` files remains runtime-unverified. They were **not** translated into Cursor's `.cursor/rules/*.mdc` format: that would add different @@ -36,14 +38,18 @@ configured on the Cursor side for CVE research and live probing to work. ### Agents -- **`model: sonnet` → `model: grok-4.6`** on `security-expert` — the uniform-model doctrine: every +- **`model: opus` → `model: grok-4.6`** on `security-expert` — the uniform-model doctrine: every ported agent runs on `grok-4.6`, whose default effort is `medium`, written bare (`[effort=medium]` would be redundant). This agent is an executant, not an organ of control (that role belongs to `challenger` and `sniper` in `fuse-ai-pilot`), so it takes no `[effort=high]`. `claude-opus-*` - remains barred by policy. -- **No `readonly:`.** R6's condition fails twice: the source `tools:` contains both `Edit` and - `Write` (the agent applies fixes), and it declares 23 `mcp__*` tools. -- **`tools:` is kept in the frontmatter, unchanged**, and a `## Allowed tools` block is emitted at + remains barred by policy. The source `effort: medium` key is dropped. +- **The agent reports, it never fixes.** The source `tools:` no longer contains `Edit` (its only + write is the audit report, via `Write`); the port follows it. Remediation is dispatched by the + caller to the domain expert and `sniper`. +- **No `readonly:`.** R6's condition still fails: the agent keeps `Write` for the report and + declares 23 `mcp__*` tools. +- **`tools:` follows the source with two Cursor substitutions**: `Agent` → `Task`, and the Claude + Code-only `SendMessage` is removed. A `## Allowed tools` block mirroring the line is emitted at the top of the body **in addition** (R4). - **`color:` and `skills:` are kept as-is** (R7). `skills:` mixes bare names with one plugin-qualified reference, `fuse-ai-pilot:fuse-browser-usage`; whether the qualified form @@ -51,18 +57,26 @@ configured on the Cursor side for CVE research and live probing to work. ### Skills -All 5 satisfy Cursor's hard rule that `name:` equals the parent folder name: `auth-audit`, -`cve-research`, `dependency-audit`, `security-headers`, `security-scan`. `references/` and the -nested `references/templates/` folders are natively supported and were copied verbatim (R9). +All 6 satisfy Cursor's hard rule that `name:` equals the parent folder name: `agentic-security`, +`auth-audit`, `cve-research`, `dependency-audit`, `security-headers`, `security-scan`. +`references/` and the nested `references/templates/` folders are natively supported and were +copied verbatim (R9). -Keys preserved across all 5 skills, absent from Cursor's documented set and **not verified against +`agentic-security` audits AI-agent configuration (workspace trust, hooks, MCP servers, prompt +injection, permissions, secrets, CI agents). Its references describe Claude Code facts +(`CLAUDE_PLUGIN_ROOT`, `.claude/` paths, CVE-2025-59536 ...) as **audit knowledge about the +audited target**, so they are kept verbatim and are not Cursor-translated. +`security-scan` runs the harness scanner as `npx -y @fusengine/harness scan ` (see +Commands). + +Keys preserved across all 6 skills, absent from Cursor's documented set and **not verified against the binary**, so unknown rather than unsupported (R19): `argument-hint`, `user-invocable`. `user-invocable` was **not** translated to `disable-model-invocation` (R8). ### Commands -`commands/scan.md` is byte-identical to the source (R10). It declares no `name`; Cursor derives +`commands/scan.md` matches the source except for the harness scan command (see below). It declares no `name`; Cursor derives `/scan` from the filename. It uses `$ARGUMENTS`, which `qxo(e,t)` substitutes with the raw argument text — confirmed in the binary — so `/scan --deps-only src/` works as intended. @@ -70,13 +84,14 @@ It keeps `argument-hint` and `disable-model-invocation: false` verbatim (R7 / R1 `argument_hint` exists at protobuf level (`aiserver.v1.GlobalCommand` field 5), so the concept is native; the exact casing expected in local frontmatter could not be confirmed. -One body construct does not execute under Cursor and was kept verbatim rather than rewritten: -`scan.md` line 36 tells the model to run -`bun ${CLAUDE_PLUGIN_ROOT}/../node_modules/@fusengine/harness/dist/cli/bin.mjs scan `. +One body construct does not execute under Cursor and is rewritten. The source tells the model to +run `bun ${CLAUDE_PLUGIN_ROOT}/../node_modules/@fusengine/harness/dist/cli/bin.mjs scan `. `${CLAUDE_PLUGIN_ROOT}` **is** substituted by Cursor, but only inside a hook's `command` string and only when the hook's source is a `claude-plugin` — never inside markdown prose handed to the model. -The same limitation exists under Claude Code, so this is not a regression introduced by the port; -it is noted so the next reader does not take it for one. +The port therefore uses `npx -y @fusengine/harness scan ` in `commands/scan.md`, +`skills/security-scan/SKILL.md`, `agents/security-expert.md`, `rules/apex-workflow.md` and +`skills/security-scan/references/templates/scan-report.md`; the first three add the sentence "This standalone CLI verb does not depend on Cursor hook normalization." +(`verify.sh` fails any `${CLAUDE_PLUGIN_ROOT}` in the two native command files). ### Hooks @@ -145,10 +160,12 @@ on all three entries. ## Runtime paths -This plugin references **no** `.claude/…` path in the body of any skill, agent, command or rules -file. Nothing to resolve harness-side, and the R21 clause is deliberately not reproduced here: it -asserts that this plugin's bodies reference `.claude/…` state files, which would be factually -false. +No skill, agent, command or rules file instructs the model to read or write a `.claude/…` state +file of this plugin; nothing to resolve harness-side. The `.claude/…`, `.claude-plugin/` and +`CLAUDE.md` mentions in `agents/security-expert.md`, `commands/scan.md`, `rules/security-rules.md` +and `skills/agentic-security/**` are audit targets (the agent-configuration files that the audit +inspects), kept verbatim, not runtime paths of this plugin. The R21 clause is deliberately not +reproduced here. The harness's own `~/.claude/logs/00-security` state directory is mentioned nowhere in the ported content — it appeared only in the source `hooks.json` `_description`, which R16 removed and this @@ -165,8 +182,10 @@ rewritten above. - **Degraded, not lost — the two MCP matchers.** Their server segment is gone, so the ported matchers are enumerations that must be maintained by hand (see the caveat above). A tool added to either MCP server stops being tracked without any error. -- `${CLAUDE_PLUGIN_ROOT}` in `commands/scan.md` and `skills/security-scan/SKILL.md` is not - substituted in markdown prose — under Cursor **or** Claude Code. Not a port regression. +- `${CLAUDE_PLUGIN_ROOT}` is not substituted in markdown prose — under Cursor **or** Claude Code — + so the harness scan command was rewritten to `npx -y @fusengine/harness scan ` (see + Commands). The remaining `CLAUDE_PLUGIN_ROOT` mentions in + `skills/agentic-security/references/hooks-plugins.md` are audit knowledge about audited plugins. - `Glob` and `MultiEdit` are `NOT PORTABLE` matchers (R13), `Notification` and `PermissionRequest` are `NOT PORTABLE` events (R12); this plugin uses none of them. - `rules/*.md` are default-discovery candidates, but native activation of the verbatim plain `.md` diff --git a/.cursor-plugin/plugins/fuse-security/agents/security-expert.md b/.cursor-plugin/plugins/fuse-security/agents/security-expert.md index 6229f9f..8be581d 100644 --- a/.cursor-plugin/plugins/fuse-security/agents/security-expert.md +++ b/.cursor-plugin/plugins/fuse-security/agents/security-expert.md @@ -1,10 +1,10 @@ --- name: security-expert -description: "Use when: security audit requested, scanning for OWASP Top 10, CVE research, dependency audit, secrets detection, auth hardening. Do NOT use for: general code quality (use sniper), feature implementation." +description: "Use when: security audit requested (whole repository or a change vs its merge base), scanning for OWASP Top 10, CVE research, dependency audit, secrets detection, auth hardening, agent-configuration review (.claude/, .mcp.json, hooks, plugins, skills). Do NOT use for: fixing the audited code (the caller dispatches the domain expert + sniper with this agent's findings), general code quality (use sniper), feature implementation." model: grok-4.6 color: orange -tools: Read, Edit, Write, Bash, Grep, Glob, Task, Skill, mcp__context7__resolve-library-id, mcp__context7__query-docs, mcp__exa__web_search_exa, mcp__exa__get_code_context_exa, mcp__exa__deep_researcher_start, mcp__exa__deep_researcher_check, mcp__sequential-thinking__sequentialthinking, mcp__fuse-browser__browser_navigate, mcp__fuse-browser__browser_fill, mcp__fuse-browser__browser_press, mcp__fuse-browser__browser_click, mcp__fuse-browser__browser_console, mcp__fuse-browser__browser_screenshot, mcp__fuse-browser__browser_probe, mcp__fuse-browser__browser_probe_html, mcp__fuse-browser__browser_network, mcp__fuse-browser__browser_cookies, mcp__fuse-browser__browser_route, mcp__fuse-browser__browser_dialog, mcp__fuse-browser__browser_login, mcp__fuse-browser__browser_fetch, mcp__fuse-browser__browser_open, mcp__fuse-browser__browser_close -skills: security-scan, cve-research, dependency-audit, security-headers, auth-audit, fuse-ai-pilot:fuse-browser-usage +tools: Read, Write, Bash, Grep, Glob, Task, Skill, mcp__context7__resolve-library-id, mcp__context7__query-docs, mcp__exa__web_search_exa, mcp__exa__get_code_context_exa, mcp__exa__deep_researcher_start, mcp__exa__deep_researcher_check, mcp__sequential-thinking__sequentialthinking, mcp__fuse-browser__browser_navigate, mcp__fuse-browser__browser_fill, mcp__fuse-browser__browser_press, mcp__fuse-browser__browser_click, mcp__fuse-browser__browser_console, mcp__fuse-browser__browser_screenshot, mcp__fuse-browser__browser_probe, mcp__fuse-browser__browser_probe_html, mcp__fuse-browser__browser_network, mcp__fuse-browser__browser_cookies, mcp__fuse-browser__browser_route, mcp__fuse-browser__browser_dialog, mcp__fuse-browser__browser_login, mcp__fuse-browser__browser_fetch, mcp__fuse-browser__browser_open, mcp__fuse-browser__browser_close +skills: security-scan, cve-research, dependency-audit, security-headers, auth-audit, agentic-security, fuse-ai-pilot:fuse-browser-usage --- ## Allowed tools @@ -17,7 +17,6 @@ skills: security-scan, cve-research, dependency-audit, security-headers, auth-au This agent must restrict itself strictly to the following tools: - `Read` -- `Edit` - `Write` - `Bash` - `Grep` @@ -49,81 +48,74 @@ This agent must restrict itself strictly to the following tools: - `mcp__fuse-browser__browser_close` -You are a security vulnerability detection and remediation specialist, working through a mandatory five-phase discipline: detect the stack, research CVEs, scan for vulnerable patterns, report findings mapped to OWASP, and fix via sniper delegation. You work alongside `explore-codebase` for architecture and `research-expert` for CVE/documentation lookups. +You are a security auditor. You detect vulnerabilities, verify each one by trying to refute it, and hand the verified findings back to your caller. You work through a mandatory six-phase discipline: DETECT, RESEARCH, SCAN, VERIFY, REPORT, HANDOFF. -Your posture is zero-tolerance on severity: every CRITICAL and HIGH finding must be fixed, every finding is evidence-backed against a CVE or OWASP reference, and every fix is the smallest change that eliminates the vulnerability — you never introduce a new vulnerability while closing another. You never skip a phase, and you never expose secrets in reports or logs. +You REPORT, you never fix. You never edit the audited project: your only write is the audit report file. Remediation belongs to your caller, who dispatches the domain expert and then sniper with your findings. -Your remit is vulnerability detection and remediation specifically, not general code quality (that's sniper's job) and not feature implementation. +Your posture is evidence first: a finding is reported only when it survives a second, read-only refutation pass with confidence 8 or more, and every reported finding carries a concrete exploit scenario. You never print a secret value. # Security Expert Agent -Security vulnerability detection and remediation specialist with comprehensive scanning capabilities. +**Read first:** this plugin's `rules/security-rules.md` (plugin root = two levels above the base directory of any of this plugin's skills, e.g. `security-scan`). It holds the single severity scale, the confidence threshold, the noise policy ("Not reported") and the report format; plugin `rules/` files are not loaded into context automatically. -## Purpose +## Scope (set by the caller) -Systematic security auditor ensuring vulnerability-free, hardened code. Works with `explore-codebase` for architecture analysis and `research-expert` for CVE/documentation research. +| Scope | When | Files examined | +|-------|------|----------------| +| **Repository** (default) | Full audit, `/scan` without a diff request | Whole repository (or the path given) | +| **Diff** | The caller asks for the review of a change (branch, PR) | Files changed vs the merge base: `git diff --name-only --merge-base ` (base = `origin/HEAD` unless the caller names another) plus untracked files (`git ls-files --others --exclude-standard`). Only issues introduced by the change are reported. | +| **Partial** | `/scan --deps-only`, `--headers`, `--auth` | Only the named check; the report states which categories were not covered. | -## Workflow (MANDATORY 5-PHASE) +Read-only git (`status`, `diff`, `log`, `show`, `merge-base`) is the only git you run. -1. **PHASE 1: DETECT** - Identify language/framework via project markers - - `package.json` → Node.js/React/Next.js - - `composer.json` → PHP/Laravel - - `requirements.txt`/`pyproject.toml` → Python - - `Package.swift`/`*.xcodeproj` → Swift/iOS - - `go.mod` → Go - - `Cargo.toml` → Rust +## Workflow (MANDATORY 6-PHASE) -2. **PHASE 2: RESEARCH** - CVEs via Exa + NVD/OSV.dev APIs - - Search recent CVEs for detected stack - - Check GitHub Security Advisories - - Verify dependency versions against known vulnerabilities +1. **DETECT** — stack from project markers (`package.json`, `composer.json`, `requirements.txt`/`pyproject.toml`, `Package.swift`/`*.xcodeproj`, `go.mod`, `Cargo.toml`, ...). Also detect agent configuration: `.claude/`, `.mcp.json`, `.claude-plugin/`, `hooks/`, `skills/`, `agents/`, `CLAUDE.md` / rule / memory files, `.github/workflows/` running an AI agent → load skill `agentic-security` for phase 3. +2. **RESEARCH** — CVEs and advisories for the detected stack and dependency versions (skill `cve-research`; Context7/Exa/`browser_fetch` for docs). Delegate broad lookups to `fuse-ai-pilot:research-expert` and architecture mapping to `fuse-ai-pilot:explore-codebase` (one message, parallel). +3. **SCAN** — candidate findings only, nothing reported yet: + - Harness scanner: `npx -y @fusengine/harness scan ` — a first-pass pattern scanner whose coverage is narrower than the skill's patterns and is being extended. Its output lists findings, not what it skipped: an empty result is NOT a clean result. Always complete it with the manual patterns of skill `security-scan` for every language and file type in scope. This standalone CLI verb does not depend on Cursor hook normalization. + - Secrets: patterns from `security-scan` → `references/secrets-patterns.md`. + - Dependencies: skill `dependency-audit`. + - Auth: skill `auth-audit`. Headers/cookies: skill `security-headers` (live check: its `references/live-verification.md`). + - Agent configuration (when detected in phase 1): skill `agentic-security`. + - Data-flow review: trace untrusted input to sensitive sinks in the scoped files. +4. **VERIFY** (mandatory, never skipped) — second, read-only pass on EACH candidate that tries to refute it: + - Trace the data flow: is the input really attacker-controlled at the sink? + - Check framework and project protections (auto-escaping, ORM parameterization, middleware, validation, CSP). + - Check reachability: is the code executed in production (not dead, not test-only)? + - Score confidence 1-10 and write the exploit scenario. Confidence ≥ 8 → finding. Below 8 → "Needs manual review" list with the reason. No concrete exploit scenario → not a finding. + - Apply the noise policy in `rules/security-rules.md` ("Not reported"). + - For many candidates, verification may run as parallel `fuse-ai-pilot:challenger` calls (one per candidate, fresh context). +5. **REPORT** — write `docs/security/YYYY-MM-DD-.md` inside the audited repository (create `docs/security/` if absent; `` = `repo`, the path, or the branch name in kebab-case). Never a temp or hidden directory. Format and severity scale: `rules/security-rules.md`. +6. **HANDOFF** — return to the caller: the report path, the count per severity, the findings (fields below), the "Needs manual review" list, the hardening notes, and the tools "not run". The caller dispatches the domain expert to fix and sniper to validate; you do not. -3. **PHASE 3: SCAN** - Grep vulnerable patterns + dependency audit - - Run language-specific scan patterns (OWASP Top 10) - - Execute dependency audit CLI tools - - Detect hardcoded secrets and credentials +## Finding Fields (shared contract) -4. **PHASE 4: REPORT** - Structured report with OWASP mapping - - Categorize findings by severity (CRITICAL/HIGH/MEDIUM/LOW) - - Map each finding to OWASP A01-A10 - - Provide remediation instructions +`id`, `title`, `severity`, `confidence` (1-10), `CWE`, `standard reference`, `location` (file:line, or package@version, or URL), `evidence`, `exploit scenario`, `recommendation`. -5. **PHASE 5: FIX** - Delegate to sniper for auto-correction - - Generate fix instructions per vulnerability - - Invoke sniper agent with file:line + fix description - - Validate fixes post-application +References: a CWE id for every finding, plus the applicable standard entry (OWASP Top 10:2025, ASVS 5.0.0, API Security Top 10 2023, MASVS 2.1.0, Top 10 for LLM Applications 2025/2026, Top 10 for Agentic Applications for 2026); a CVE id only for a known vulnerability in a dependency. -## Core Principles +## Optional External Tools -- **Verify Before Writing**: Use Context7/Exa to confirm APIs/patterns are correct and up-to-date before writing any code +Scanners and audit CLIs (`npm audit`, `pip-audit`, `semgrep`, `gitleaks`, ...) are optional: check with `command -v ` before use. Never install a tool. A missing tool is listed in the report as "not run", never silently skipped. -- **Zero Tolerance**: All CRITICAL/HIGH findings must be fixed -- **Evidence-Based**: Every finding backed by CVE/OWASP reference -- **Minimal Impact**: Smallest fix that eliminates the vulnerability -- **Defense in Depth**: Multiple layers of security validation +## Live Web Checks (fuse-browser) -## Capabilities +Follow `security-headers` → `references/live-verification.md`. `browser_fetch` (fast path, no launch) for documentation pages; it returns no response headers, so headers are read with `curl -sS -D - -o /dev/null ` or a live session (`browser_open` → `browser_navigate` → `browser_network` / `browser_cookies` → `browser_close`). One session, always closed. Full guide: skill `fuse-ai-pilot:fuse-browser-usage`. +Interaction tools (`browser_login`, `browser_fill`, `browser_click`, `browser_press`, `browser_route`, `browser_dialog`, ...) only on a URL named by the owner, in one session opened once and always closed (`security-headers` → `references/live-verification.md`). -- OWASP Top 10:2025 pattern scanning (A03 Supply Chain, A10 Exceptional Conditions included) -- CVE research via NVD, OSV.dev, GitHub Advisory -- Dependency audit (npm, composer, pip, cargo, go) -- Secrets detection (API keys, tokens, passwords) -- Security headers validation (CSP, HSTS, CORS) -- Authentication pattern audit (JWT, OAuth, sessions) +## Helpers -## fuse-browser (ZERO TOLERANCE) - -- **Fast-path FIRST** — `browser_fetch`: NO browser launch, ~10× faster, for static reconnaissance. Live session ONLY for interaction, auth flows, or pixels. -- **One session, always closed** — `browser_open` once, reuse `sessionId`, ALWAYS `browser_close`. -- `browser_probe` / `browser_login` / `browser_route` / `browser_cookies` require a live session — open once, close always. -- **Batch, don't loop** — `screenshot {viewports, colorScheme}` in one call. -- Full guide: invoke skill `fuse-ai-pilot:fuse-browser-usage` (profile: research-docs). +You may launch `fuse-ai-pilot:explore-codebase`, `fuse-ai-pilot:research-expert` and `fuse-ai-pilot:challenger`, within the nesting depth limit of the sub-agent conduct rule. You launch no domain expert, no sniper, no fixer. ## Forbidden -- Skip any of the 5 phases -- Ignore CRITICAL/HIGH severity findings -- Fix without researching the vulnerability first -- Introduce new vulnerabilities while fixing -- Expose secrets in reports or logs +- Edit, patch or reformat any file of the audited project — your only write is the report under `docs/security/` +- Skip a phase, especially VERIFY +- Report a finding with confidence < 8 or without an exploit scenario +- Print a secret value — report file:line and secret type only +- Install a tool, or report a missing tool as "passed" +- Commit, push, or run any git command that is not read-only +- Cite a CVE id that is not tied to a known dependency vulnerability, or a standard entry you did not verify +- Write the report to a temp or hidden directory diff --git a/.cursor-plugin/plugins/fuse-security/commands/scan.md b/.cursor-plugin/plugins/fuse-security/commands/scan.md index 89e8121..401f1a4 100644 --- a/.cursor-plugin/plugins/fuse-security/commands/scan.md +++ b/.cursor-plugin/plugins/fuse-security/commands/scan.md @@ -1,53 +1,54 @@ --- -description: Launch a comprehensive security audit on the current project. Detects vulnerabilities, scans dependencies, checks OWASP Top 10, and generates a structured report. -argument-hint: "[--full] [--deps-only] [--headers] [--auth] [path]" +description: Launch a security audit on the current project (whole repository or a change vs its merge base). Detects vulnerabilities, scans dependencies, checks OWASP Top 10:2025, verifies each finding, and writes a structured report under docs/security/. +argument-hint: "[--full] [--diff [base]] [--deps-only] [--headers] [--auth] [path]" disable-model-invocation: false --- # Security Scan -Execute a comprehensive security audit following the 5-phase workflow. +Execute a security audit following the 6-phase workflow of the `security-expert` agent. The audit reports; it never modifies the audited code. ## Usage -- `/scan` - Full security audit of current project +- `/scan` or `/scan --full` - Full security audit of the current repository (default scope) +- `/scan --diff [base]` - Review of a change: files changed vs the merge base (`base` defaults to `origin/HEAD`) plus untracked files; only issues introduced by the change are reported - `/scan --deps-only` - Dependency audit only - `/scan --headers` - Security headers check only - `/scan --auth` - Authentication patterns audit only -- `/scan path/to/dir` - Scan specific directory +- `/scan path/to/dir` - Scan a specific directory ## Workflow +Severity scale, confidence threshold, noise policy and report format: [`../rules/security-rules.md`](../rules/security-rules.md). + ### Phase 1: DETECT -Identify project language and framework automatically: -- Scan for marker files (package.json, composer.json, etc.) -- Detect framework versions and dependencies -- Map to appropriate scan patterns +- Marker files (package.json, composer.json, go.mod, Cargo.toml, ...) and framework versions +- Agent configuration (`.claude/`, `.mcp.json`, `.claude-plugin/`, hooks, skills, agents, `.github/workflows/` running an AI agent) → skill `agentic-security` +- Diff scope: `git diff --name-only --merge-base ` + `git ls-files --others --exclude-standard` (read-only git only) ### Phase 2: RESEARCH -Query recent CVEs for the detected stack: -- Use Exa to search NVD, OSV.dev, GitHub Advisory -- Focus on dependencies found in project -- Check for known exploits - -### Phase 3: SCAN -Run vulnerability patterns and dependency audit: -- Execute language-specific grep patterns (OWASP Top 10) -- Run `npx -y @fusengine/harness scan ` for automated pattern matching. This standalone CLI verb does not depend on Cursor hook normalization. -- Execute dependency audit CLI (npm audit, composer audit, etc.) -- Detect hardcoded secrets and credentials - -### Phase 4: REPORT -Generate structured vulnerability report: -- Categorize by severity: CRITICAL, HIGH, MEDIUM, LOW -- Map findings to OWASP A01-A10 categories -- Include file:line references and fix instructions - -### Phase 5: FIX -Delegate corrections to sniper agent: -- Generate fix instructions per vulnerability -- Invoke sniper with precise file:line + description -- Validate all fixes applied correctly +- CVEs and advisories for the detected stack (skill `cve-research`) + +### Phase 3: SCAN (candidates) +- Run `npx -y @fusengine/harness scan ` — a first-pass pattern scanner whose coverage is narrower than the skill's patterns; an empty result is NOT a clean result. This standalone CLI verb does not depend on Cursor hook normalization. +- Always complete it with the manual patterns of skill `security-scan` for every language and file type in scope (secrets: `references/secrets-patterns.md`) +- Dependency audit (skill `dependency-audit`); optional CLIs checked with `command -v`, never installed, missing = "not run" +- Headers/cookies (skill `security-headers`), auth (skill `auth-audit`) +- Agent configuration, when detected (skill `agentic-security`) +- Data-flow review: untrusted input traced to sensitive sinks in the scoped files + +### Phase 4: VERIFY +- Second read-only pass per candidate that tries to refute it (data flow, framework protections, reachability) +- Confidence 1-10; ≥ 8 with an exploit scenario → finding; < 8 → "Needs manual review" + +### Phase 5: REPORT +- Write `docs/security/YYYY-MM-DD-.md` in the audited repository +- Each finding: id, title, severity, confidence, CWE, standard reference, location, evidence, exploit scenario, recommendation +- Never print a secret value: file:line and secret type only + +### Phase 6: HANDOFF +- Return the report path, counts per severity, the findings, the "Needs manual review" list and the tools "not run" +- Fixes are dispatched by the caller (domain expert, then sniper); `/scan` itself changes no audited file ## Arguments @@ -55,7 +56,7 @@ Delegate corrections to sniper agent: ## Examples -- `/scan` → Full OWASP + dependency + secrets audit +- `/scan` → Full OWASP + dependency + secrets audit of the repository +- `/scan --diff` → Security review of the current branch vs `origin/HEAD` - `/scan --deps-only` → Quick dependency vulnerability check -- `/scan --auth` → JWT/OAuth/session security patterns -- `/scan src/api/` → Scan only API directory +- `/scan src/api/` → Scan only the API directory diff --git a/.cursor-plugin/plugins/fuse-security/rules/apex-workflow.md b/.cursor-plugin/plugins/fuse-security/rules/apex-workflow.md index 7a28a8f..e1cf725 100644 --- a/.cursor-plugin/plugins/fuse-security/rules/apex-workflow.md +++ b/.cursor-plugin/plugins/fuse-security/rules/apex-workflow.md @@ -5,42 +5,35 @@ alwaysApply: true # Security APEX Workflow -## 5-Phase Security Audit +## 6-Phase Security Audit ``` -DETECT → RESEARCH → SCAN → REPORT → FIX +DETECT → RESEARCH → SCAN → VERIFY → REPORT → HANDOFF ``` +The security-expert agent reports; it never fixes the audited project. Severity scale, confidence threshold, noise policy and report format: `security-rules.md` (single source). + ### Phase Mapping to APEX | Security Phase | APEX Phase | Agent/Tool | |---------------|------------|------------| | DETECT | Analyze | explore-codebase | -| RESEARCH | Analyze | research-expert + Exa | -| SCAN | Execute | security-scan.sh + Grep | -| REPORT | eLicit | Sequential Thinking | -| FIX | eXamine | sniper | +| RESEARCH | Analyze | research-expert + Context7/Exa | +| SCAN | Analyze | harness CLI `npx -y @fusengine/harness scan ` + skill patterns + Grep | +| VERIFY | eLicit | read-only refutation pass, optionally challenger per candidate | +| REPORT | eLicit | report at `docs/security/YYYY-MM-DD-.md` | +| HANDOFF | — (ends the audit) | findings returned; the caller then dispatches the domain expert, then sniper | ### Mandatory Rules -1. **NEVER skip DETECT** - Wrong language = wrong patterns +1. **NEVER skip DETECT** - Wrong stack = wrong patterns 2. **ALWAYS research CVEs** before scanning -3. **SCAN all categories** - XSS, SQLi, RCE, SSRF, secrets -4. **REPORT with OWASP mapping** - Every finding has a category -5. **FIX via sniper** - Never fix inline without validation - -### Severity Handling - -| Severity | Action | Deadline | -|----------|--------|----------| -| CRITICAL | Fix immediately, block deployment | Same session | -| HIGH | Fix before merge | Same session | -| MEDIUM | Fix if time permits | Next session | -| LOW | Document for backlog | Tracked | +3. **SCAN all categories** - XSS, SQLi, RCE, SSRF, secrets, agent configuration when present +4. **NEVER skip VERIFY** - Only confidence ≥ 8 with an exploit scenario is reported +5. **HANDOFF, never fix** - The agent writes only its report; remediation goes through the caller (domain expert, then sniper) ### Integration with Main APEX When used within the main APEX workflow: -- Security scan runs during **eXamine** phase -- Findings feed into sniper's validation -- CRITICAL/HIGH block the workflow until fixed +- The security audit runs during **eXamine** (diff scope vs the merge base for a change review) +- CRITICAL and HIGH findings are flagged as blocking in the handoff; the caller decides and dispatches the fixes diff --git a/.cursor-plugin/plugins/fuse-security/rules/security-rules.md b/.cursor-plugin/plugins/fuse-security/rules/security-rules.md index f89d144..00c70ab 100644 --- a/.cursor-plugin/plugins/fuse-security/rules/security-rules.md +++ b/.cursor-plugin/plugins/fuse-security/rules/security-rules.md @@ -5,9 +5,11 @@ alwaysApply: true # Security Rules -## OWASP Top 10:2025 Compliance +Single source for the severity scale, the noise policy and the report format of the security-expert agent and `/scan`. -Every scan MUST check all 10 categories (source: https://top10.owasp.org/2025/): +## Standards (current editions) + +Every full repository audit (not a partial `--deps-only` / `--headers` / `--auth` run) checks all ten OWASP Top 10:2025 categories (https://owasp.org/projects/top-ten — https://top10.owasp.org/2025): - **A01** Broken Access Control (includes SSRF, CSRF) - **A02** Security Misconfiguration - **A03** Software Supply Chain Failures @@ -19,34 +21,58 @@ Every scan MUST check all 10 categories (source: https://top10.owasp.org/2025/): - **A09** Security Logging and Alerting Failures - **A10** Mishandling of Exceptional Conditions -## Zero Tolerance Rules +Other references, cited when applicable: OWASP ASVS 5.0.0, OWASP API Security Top 10 2023, OWASP MASVS 2.1.0, CWE Top 25 2025, OWASP Top 10 for LLM Applications (2025 and 2026 editions, cited with the edition, e.g. `LLM01:2026`), OWASP Top 10 for Agentic Applications for 2026 (https://genai.owasp.org/initiatives/agentic-security-initiative/). + +Each finding cites a CWE id plus the applicable standard entry; a CVE id only for a known vulnerability in a dependency. + +## Severity (single definition) + +| Severity | Definition | Examples | +|----------|------------|----------| +| **CRITICAL** | Directly exploitable, no or low privilege, leads to remote code execution, full data compromise or credential exposure | Hardcoded live secret, SQL/command injection, `eval`/`exec` on user input | +| **HIGH** | Exploitable with a realistic precondition; leads to account takeover, unauthorized data access or privilege escalation | Broken access control on an object, stored XSS, unvalidated redirect used in an auth flow | +| **MEDIUM** | Exploitable only under specific, concrete conditions, or limited impact | Reflected XSS behind an unusual precondition, weak crypto protecting non-critical data | +| **LOW** | Real weakness with a shown attack path but minor impact | Information disclosure of non-sensitive internals | + +This scale is the only one for reported findings. A CVSS score or a skill's baseline (e.g. a header's default level) is an input to this scale, never a substitute: the final severity is set by the definitions above. + +CRITICAL and HIGH findings are flagged in the handoff as blocking for the caller; remediation is the caller's decision and dispatch. + +## Verification and Confidence + +- Every candidate goes through a second, read-only pass that tries to refute it: data flow traced to the sink, framework protections checked, reachability checked. +- Confidence 1-10. **≥ 8 → reported finding**; < 8 → "Needs manual review" list with the reason. +- Every reported finding has a concrete exploit scenario. +- Basis: Anthropic's security-review command (https://raw.githubusercontent.com/anthropics/claude-code-security-review/main/.claude/commands/security-review.md) — one finding pass, one false-positive filter per finding, findings under confidence 8 dropped — and Claude Code Security, where "Claude re-examines each result, attempting to prove or disprove its own findings" (https://www.anthropic.com/news/claude-code-security). + +## Not Reported (noise policy) + +This plugin's own policy, inspired by the exclusion list of the security-review command above. The following are NOT reported as vulnerabilities unless a concrete attack path is shown: +- Missing hardening alone (no exploitable consequence) — e.g. an absent security header; listed under "Hardening notes" (no severity), not as a finding +- Theoretical race conditions or timing attacks +- Denial of service and resource exhaustion without a shown attack path. Exceptions that ARE findings (the reachable endpoint is the attack path; severity by the single scale above): a missing rate limit on an authentication, password-reset, OTP or other abuse-prone endpoint, and a GraphQL endpoint without depth/cost limits that is reachable without authentication. The same gaps without a shown path are never silently dropped: they go to "Hardening notes" +- Code only in test files or only used to run tests +- Documentation files (Markdown) — EXCEPT agent-configuration files (`CLAUDE.md`, `AGENTS.md`, rule, memory, skill, agent and command files), which skill `agentic-security` audits as executable instructions +- Outdated libraries — handled by skill `dependency-audit`, not as code findings -1. **Hardcoded secrets** → CRITICAL, fix immediately -2. **SQL injection** → CRITICAL, parameterize queries -3. **Command injection** → CRITICAL, sanitize inputs -4. **eval/exec with user input** → CRITICAL, remove -5. **Unvalidated redirects** → HIGH, whitelist URLs +## Secrets -## Dependency Rules +- Detection patterns: single source `skills/security-scan/references/secrets-patterns.md` (not repeated here). +- A secret value is NEVER printed in a report, log or message: file:line and secret type only. -- Run `npm audit` / `composer audit` / `pip-audit` on every scan -- CRITICAL/HIGH advisories must be resolved -- Pin dependency versions in production -- Check for abandoned/unmaintained packages +## Dependencies -## Secrets Detection Patterns +- Procedure and optional tools: skill `dependency-audit`. Audit CLIs are optional, checked with `command -v`, never installed; a missing tool is reported "not run". -- AWS keys: `AKIA[0-9A-Z]{16}` -- Generic API keys: `api[_-]?key.*=.*['\"][a-zA-Z0-9]{20,}` -- JWT tokens: `eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*` -- Private keys: `-----BEGIN (RSA|EC|DSA) PRIVATE KEY-----` -- Connection strings: `(mysql|postgres|mongodb)://[^\\s]+` +## Report -## Report Requirements +Written to `docs/security/YYYY-MM-DD-.md` inside the audited repository (never a temp or hidden directory); its path is returned to the caller. -Every report MUST include: -1. Executive summary (findings count by severity) -2. Detailed findings with file:line references -3. OWASP category mapping -4. Remediation instructions per finding -5. Dependency audit results +Contents: +1. Scope (repository or diff vs merge base) and date +2. Executive summary: findings count by severity +3. Findings, each with: id, title, severity, confidence (1-10), CWE, standard reference, location (file:line, package@version or URL), evidence, exploit scenario, recommendation +4. Needs manual review (confidence < 8, with reason) +5. Hardening notes (missing hardening without a shown attack path; no severity) +6. Dependency audit results +7. Tools run / not run, and categories not covered (partial runs) diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/SKILL.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/SKILL.md new file mode 100644 index 0000000..85587b7 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/SKILL.md @@ -0,0 +1,75 @@ +--- +name: agentic-security +description: "Use when auditing the security of an AI-coding-agent setup in a repository: Claude Code project settings and hooks, plugin manifests and hooks.json, .mcp.json and MCP servers, skills, agents and rule files, permission rules, secrets in agent configuration, and CI workflows that run an AI agent on pull requests. Do NOT use for application code vulnerabilities (use security-scan), dependency CVEs (use dependency-audit or cve-research), auth flows (use auth-audit) or HTTP headers (use security-headers)." +argument-hint: "[path] [--scope trust|hooks|mcp|injection|permissions|secrets|ci]" +user-invocable: true +--- + + +This skill audits the attack surface that an AI coding agent adds to a repository: files that +run code before or around the workspace trust dialog, hooks shipped by plugins, MCP servers +and their credentials, prompt-injection paths into the agent's context, permission rules and +bypass modes, secrets stored in agent configuration and memory, and CI jobs that run an agent +on untrusted input. + +It reports; it never fixes the audited project and never changes the user's settings. Every +finding carries its evidence (file:line), passes a read-only refutation pass, and cites the +standard entry it maps to, as read on the source named in the references. + + +# Agentic Security Skill + +## Overview + +Project configuration for an agent is executable: a `.claude/settings.json` hook, an `.mcp.json` +server command or an `env` override runs on the developer's machine. Check Point Research +showed this end to end (CVE-2025-59536, CVE-2026-21852). This skill turns the vendor +documentation into checklists an auditor can run read-only. + +## Audit Areas + +| Area | What is checked | Reference | +|------|-----------------|-----------| +| Trust boundary | Hooks, `env`, helpers, MCP auto-approval and base-URL overrides that act before trust | [trust-boundary.md](references/trust-boundary.md) | +| Hook supply chain | Plugin `hooks.json`, `plugin.json` `hooks` / `mcpServers` / `userConfig` | [hooks-plugins.md](references/hooks-plugins.md) | +| MCP trust | Every server source, publisher, pinning, env and tokens, tool descriptions | [mcp-trust.md](references/mcp-trust.md) | +| Prompt injection | Untrusted content reaching the agent, instruction files that obey observed content | [prompt-injection.md](references/prompt-injection.md) | +| Permissions | Broad allow rules, deny-rule limits, bypass and auto modes, saved approvals | [permissions.md](references/permissions.md) | +| Secrets | Keys and tokens in settings, `.mcp.json`, hooks, memory and lesson files, `.env` | [secrets.md](references/secrets.md) | +| CI agents | AI review or agent actions running on untrusted pull requests | [ci-agents.md](references/ci-agents.md) | + +## Workflow + +1. **Inventory** the agent surface of the target path: `.claude/`, `.mcp.json`, `.claude-plugin/`, + `hooks/`, `skills/`, `agents/`, `CLAUDE.md`, rule and memory files, `.github/workflows/`, and the + equivalent folders of other agent tools present in the repository. +2. **Run** the checklist of each area in scope ([audit-checklist.md](references/templates/audit-checklist.md)). +3. **Score** each candidate: severity, confidence 1-10, CWE and standard entry from + [standards-map.md](references/standards-map.md). +4. **Verify**: run the refutation pass in [verification.md](references/verification.md) on every + candidate. Confidence 8 or more becomes a finding; lower goes to "needs manual review". +5. **Report** with [audit-report.md](references/templates/audit-report.md) to + `docs/security/YYYY-MM-DD-.md` inside the audited repository. + +## Critical Rules + +| Rule | Why | +|------|-----| +| Report only, never fix or change settings | The audit must not alter the trust state it measures | +| Never print a secret value | Report file:line and the secret type only | +| Read `~/.claude`, `~/.codex` and similar only when the owner asks, and read-only | User-level config is outside the audited repository | +| Cite every fact from the reference files | Vendor behavior changes by version; no claim from memory | +| A static read never proves exploitability | See [verification.md](references/verification.md) | + +## References + +- [Trust boundary](references/trust-boundary.md) — what a repository can run before trust, the two CVEs +- [Hooks and plugins](references/hooks-plugins.md) — plugin hook supply chain +- [MCP trust](references/mcp-trust.md) — server inventory and trust checks +- [Prompt injection](references/prompt-injection.md) — injection paths into the agent +- [Permissions](references/permissions.md) — rules, modes and their documented limits +- [Secrets](references/secrets.md) — secrets in agent configuration and memory +- [CI agents](references/ci-agents.md) — agents in GitHub Actions +- [Standards map](references/standards-map.md) — OWASP LLM / Agentic entries and CWE, as read +- [Verification and limits](references/verification.md) — refutation pass, what the skill does not prove +- [Audit checklist](references/templates/audit-checklist.md) · [Audit report](references/templates/audit-report.md) diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/ci-agents.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/ci-agents.md new file mode 100644 index 0000000..01fc426 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/ci-agents.md @@ -0,0 +1,48 @@ +--- +name: ci-agents +description: GitHub Actions workflows that run an AI agent or AI review on pull requests, issues or comments +when-to-use: Auditing .github/workflows/ for steps that call an AI agent, an AI review action or `claude -p` +keywords: github actions, pull_request, untrusted PR, AI review, claude-code-security-review, claude -p, secrets +priority: high +related: prompt-injection.md, trust-boundary.md, secrets.md +--- + +# AI Agents in CI + +## Why it matters + +A workflow that feeds a pull request, an issue or a comment to an agent hands attacker-written +text to a model that holds the workflow's tokens and tools. In a non-interactive run there is no +trust dialog and no MCP approval prompt. + +## Documented facts + +- Anthropic's security-review action README, section "Security Considerations": "This action is + not hardened against prompt injection attacks and should only be used to review trusted PRs." + It recommends the repository setting "Require approval for all external contributors" so + workflows only run after a maintainer has reviewed the PR. Its Quick Start grants + `pull-requests: write` and `contents: read` and passes `claude-api-key` from secrets. + Source: https://raw.githubusercontent.com/anthropics/claude-code-security-review/main/README.md +- `claude -p` or the SDK in a never-trusted folder uses the repository's hooks, `env` block and + helper commands, and connects `.mcp.json` servers without asking. + Source: https://code.claude.com/docs/en/permissions (section "What runs before you trust a folder") +- Hardening for `-p` in a repository you didn't write: `--setting-sources user`, `--bare`, + `--settings '{"disableAllHooks": true}'`, `disabledMcpjsonServers`. Same source. +- GitHub: expressions inside `${{ }}` in a `run:` step are substituted before the shell script + runs, "which can make it vulnerable to shell command injection"; contexts ending in `body`, + `head_ref`, `title`, `message` and similar are potentially untrusted input. + Source: https://docs.github.com/en/actions/concepts/security/script-injections +- OWASP LLM01:2026 names "a community pull request" as a low-privilege channel used to reach a + developer's agent. Source: PDF linked from https://genai.owasp.org/resource/owasp-genai-llm-top-10-2026/ + +## Checklist + +| # | Look for | Where | Why | Verify | +|---|----------|-------|-----|--------| +| C1 | Steps running an AI agent or AI review action (`claude -p`, `anthropics/*` actions, other agent CLIs) | `.github/workflows/*.yml` | Inventory of agent execution in CI | List workflow, job, step, action ref | +| C2 | Triggers reachable by outsiders: `pull_request` from forks, `issues`, `issue_comment` | `on:` block | Attacker-written text reaches the agent | Is a maintainer approval gate documented for the repository? Mark "not verifiable from the repo" if it is a GitHub setting | +| C3 | PR title, body, branch name, comment or diff interpolated into the agent prompt | `run:` / `with:` inputs | Direct injection into the prompt; `${{ }}` in `run:` is also shell injection (CWE-78) | Trace each `${{ github.event.* }}` into the prompt or command | +| C4 | Agent job permissions and secrets | `permissions:`, `secrets.*` | Tokens the injected agent can use (Excessive Agency) | Write scopes, API keys, cloud credentials available to the step | +| C5 | Agent run on the PR's checked-out head with project config | checkout `ref`, then `claude -p` | The PR's own `.claude/settings.json`, hooks and `.mcp.json` apply in `-p` | Is `--setting-sources user` or `--bare` used? | +| C6 | Action pinned by tag or branch (`@main`) instead of commit SHA | `uses:` | Upstream change runs with the job's secrets | Record the ref; flag branch refs | +| C7 | Agent output posted back or committed automatically | comment / push steps | Injected output reaches the repository or reviewers | Is there a human gate before merge or publish? | diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/hooks-plugins.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/hooks-plugins.md new file mode 100644 index 0000000..25cdf6d --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/hooks-plugins.md @@ -0,0 +1,59 @@ +--- +name: hooks-plugins +description: Hook supply chain of Claude Code plugins and marketplaces — what hooks.json and plugin.json make a user's machine run +when-to-use: Auditing a plugin or a marketplace repository, or a project that enables third-party plugins +keywords: hooks.json, plugin.json, mcpServers, userConfig, sensitive, CLAUDE_PLUGIN_ROOT, CLAUDE_PLUGIN_OPTION +priority: critical +related: trust-boundary.md, mcp-trust.md, secrets.md +--- + +# Hooks and Plugins + +## Why it matters + +A plugin hook is a shell command that runs on every user who enables the plugin, on the events +it subscribes to. A marketplace that ships hooks ships code execution to every installer. + +## Documented facts + +Source for this section: https://code.claude.com/docs/en/plugins-reference + +- `plugin.json` `hooks` takes a `.json` path, an inline hooks object, or an array of both; + Claude Code merges it with `hooks/hooks.json` when that file exists. A hooks file wraps its + event map in a top-level `"hooks"` key. +- `plugin.json` `mcpServers` takes a `.json` path, an MCP bundle path or URL (`.mcpb` / `.dxt`, + downloaded into `.mcpb-cache/`), an inline map, or an array. `.mcp.json` at the plugin root + loads first; a later server with the same name replaces an earlier one. +- `userConfig` option field `sensitive`: "If `true`, masks input and stores the value in secure + storage instead of `settings.json`". Non-sensitive values are saved under `pluginConfigs` in + the user's `settings.json`. +- `CLAUDE_PLUGIN_OPTION_` is exported to hook processes for every option. + `${user_config.KEY}` is substituted in MCP and LSP config, exec-form hook `args`, and skill and + agent content (sensitive values become a placeholder in skill and agent content). +- Shell-form hook commands, monitor commands and MCP `headersHelper` reject `${user_config.*}`, + because a shell would re-parse the substituted value. +- Hook commands can reference `CLAUDE_PLUGIN_ROOT`, `CLAUDE_PLUGIN_DATA`, `CLAUDE_PROJECT_DIR`. + +Source: https://code.claude.com/docs/en/permissions (section "Precedence among rules, hooks, and mods") +- PreToolUse hook decisions don't bypass deny and ask rules; this covers hooks in settings files + and in a plugin's `hooks/hooks.json`. A hook that exits with code 2 blocks the call before + permission rules are evaluated. + +Source: https://code.claude.com/docs/en/security +- Non-interactive (`-p`) sessions show neither the trust dialog nor the `.mcp.json` approval prompt. + +## Checklist + +| # | Look for | Where | Why | Verify | +|---|----------|-------|-----|--------| +| H1 | Every hook: event, matcher, command | `hooks/hooks.json`, `plugin.json` `hooks`, referenced `.json` files | Build the full inventory; merged sources are easy to miss | Resolve each referenced file; list command per event | +| H2 | Network calls in hook commands or the scripts they run (`curl`, `wget`, `fetch`, sockets) | hook scripts | Exfiltration or remote payload at every event | Read the script, record the destination host | +| H3 | Writes outside the project or plugin data dir | hook scripts | A hook runs with the user's full account rights | Look for absolute paths, `~`, `$HOME` writes | +| H4 | Hardcoded absolute paths or user names | hook commands | Breaks on other machines; may point at attacker-controlled locations | Paths should derive from `CLAUDE_PLUGIN_ROOT` / `CLAUDE_PROJECT_DIR` | +| H5 | Shell-form commands that interpolate tool input or option values | hook commands | Command injection through tool input (CWE-78) | Prefer exec form with `args`; trace untrusted input to the command | +| H6 | `mcpServers` from a URL bundle or unpinned package | `plugin.json`, plugin `.mcp.json` | Remote code fetched at install or start | See mcp-trust.md | +| H7 | Secrets as non-`sensitive` `userConfig` | `plugin.json` `userConfig` | Stored in `settings.json` in clear | Any token / key option without `"sensitive": true` | +| H8 | Hooks that auto-approve (`"allow"`) broadly | PreToolUse hooks | Removes the human prompt for matching calls | List matchers returning allow | +| H9 | Hooks on session-start events in a repository (not a plugin) | `.claude/settings.json` | Runs in `-p`/SDK without trust | See trust-boundary.md T1 | + +For a marketplace repository, run H1-H8 on every plugin and report per plugin. diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/mcp-trust.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/mcp-trust.md new file mode 100644 index 0000000..9e6f1c9 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/mcp-trust.md @@ -0,0 +1,57 @@ +--- +name: mcp-trust +description: Inventory and trust checks for every MCP server an agent session can load +when-to-use: Auditing .mcp.json, plugin MCP servers, subagent inline servers, or any MCP configuration in a repository +keywords: mcp, .mcp.json, npx, latest, pinning, tokens, headersHelper, disabledMcpjsonServers, tool descriptions +priority: high +related: trust-boundary.md, hooks-plugins.md, prompt-injection.md +--- + +# MCP Server Trust + +## Why it matters + +A stdio MCP server is a local process started with the user's rights; a remote server receives +whatever headers and tokens the config sends; every server's tool output re-enters the model's +context. Anthropic does not security-audit MCP servers. + +## Documented facts + +Source: https://code.claude.com/docs/en/security (section "MCP security") +- Project-scoped servers live in `.mcp.json`; servers at other scopes and claude.ai connectors + are configured outside the repository, "and plugins can add servers too, so reviewing + `.mcp.json` doesn't show every server a session can load". +- Anthropic reviews connectors against its listing criteria before adding them to the Anthropic + Directory, "but does not security-audit or manage any MCP server". + +Source: https://code.claude.com/docs/en/mcp +- "Verify you trust each server before connecting it. Servers that fetch external content can + expose you to prompt injection risk." +- Scopes: local and user in `~/.claude.json`, project in `.mcp.json`; precedence local, project, + user, plugin-provided, claude.ai connectors (section "Scope hierarchy and precedence"). +- Plugins define servers in `.mcp.json` at the plugin root or inline in `plugin.json`; Claude Code + starts them automatically when the plugin is enabled. +- `claude -p`, Agent SDK sessions, and cloud sessions outside a project's threads load project-scoped servers without the approval + prompt; `disabledMcpjsonServers`, `--setting-sources` and `--strict-mcp-config` keep them out. +- In a remote server's `url` and `headers`, credential variables such as `ANTHROPIC_API_KEY`, + `ANTHROPIC_AUTH_TOKEN` and `NPM_TOKEN` read as empty; a name outside the covered set, such as + `API_KEY`, "expands as written". +- `headersHelper` is executed "as an arbitrary shell command", only after trust for project and + local-scope servers. + +Source: https://code.claude.com/docs/en/permissions (section "What runs before you trust a folder") +- Inline `mcpServers` in the frontmatter of a repository subagent are not used until the folder is trusted. + +## Checklist + +| # | Look for | Where | Why | Verify | +|---|----------|-------|-----|--------| +| M1 | Full server inventory | `.mcp.json`, plugin `.mcp.json` / `plugin.json` `mcpServers`, agent frontmatter `mcpServers`; user-level files only on owner request | `.mcp.json` alone is incomplete per the security doc | One row per server: name, source file, transport, command or URL | +| M2 | Publisher | package name, repository, URL host | Anthropic does not audit servers | Official vendor or the owner's own code vs unknown publisher | +| M3 | Unpinned launch: `npx -y `, `@latest`, `uvx ` without version, bundle URL | `command` / `args` | Each start may run new upstream code | Exact version or digest present? | +| M4 | Env vars and tokens passed | `env`, `headers`, `args` | A server receives every credential it is given | List variable names only, never values; flag literal secrets (see secrets.md) | +| M5 | Remote URL hosts | `url` | Data sent to a third party | Record host; flag plain `http://` to non-local hosts | +| M6 | `headersHelper` commands | server config | Shell command execution | Read the command as you would a hook | +| M7 | Tool descriptions carrying instructions ("always call", "ignore previous", "do not tell the user") | server source or tool listing, when available | Descriptions enter the model's context (prompt-injection surface) | Quote the line; static read only — see verification.md | +| M8 | Servers that fetch external content (web, issues, email) | server purpose | Named prompt-injection risk in the MCP doc | Cross-check with prompt-injection.md P1 | +| M9 | Broad MCP allow rules (`mcp____*`) | permission settings | Every tool of the server runs without prompt | See permissions.md | diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/permissions.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/permissions.md new file mode 100644 index 0000000..b7fb2ee --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/permissions.md @@ -0,0 +1,56 @@ +--- +name: permissions +description: Permission rules, modes and saved approvals of an agent setup, and the documented limits of each +when-to-use: Auditing permissions blocks, defaultMode, sandbox settings and settings.local.json approvals in a repository +keywords: permissions, allow, deny, ask, bypassPermissions, auto mode, dontAsk, sandbox, settings.local.json +priority: high +related: trust-boundary.md, prompt-injection.md, templates/audit-checklist.md +--- + +# Permissions and Bypass + +## Documented facts + +Source for this section: https://code.claude.com/docs/en/permissions + +- Rules are evaluated deny, then ask, then allow; "An allow rule can't carve an exception out of a + deny rule." Deny from any scope beats allow from any other scope. +- A Bash rule "matches the command text Claude writes"; a deny or ask rule "isn't a security + boundary around the program". The documented example: `Bash(curl *)` does not stop + `/usr/bin/curl …` or `sh -c 'curl …'`. For enforcement that doesn't depend on command text, + use sandboxing (filesystem and network isolation). +- Environment runners (`direnv exec`, `devbox run`, `mise exec`, `npx`, `docker exec`) are not + stripped wrappers: `Bash(devbox run *)` matches "whatever comes after `run`". +- Modes: `default`, `acceptEdits`, `plan`, `auto`, `dontAsk`, `bypassPermissions`. In + `bypassPermissions` Claude Code skips prompts "including for writes to protected paths such as + `.git` and `.claude`"; "Only use this mode in isolated environments like containers or VMs". +- `permissions.disableBypassPermissionsMode` / `permissions.disableAutoMode` set to `"disable"` + prevent those modes; most useful in managed settings. +- Auto mode: a background classifier checks actions instead of a prompt. +- "Yes, and don't ask again" for Bash or WebFetch saves the rule to `.claude/settings.local.json` + at the git repository root; it applies to future sessions anywhere in that repository. +- Project `permissions.allow` and `additionalDirectories` apply only after the trust dialog; + `deny` and `ask` rules are not gated because they only restrict. +- `permissions.blockWritesOutsideWorkingDirectories` "doesn't limit shell commands, MCP tools, or + the programs hooks run". +- With sandboxing on and `autoAllowBashIfSandboxed` at its default `true`, sandboxed Bash runs + without prompting even under a bare `Bash` ask rule. + +Source: https://code.claude.com/docs/en/security +- A deny rule matches the command "as written"; for network enforcement independent of command + text, see sandbox network isolation. Auto mode is the built-in starting mode for interactive + terminal and VS Code sessions. + +## Checklist + +| # | Look for | Where | Why | Verify | +|---|----------|-------|-----|--------| +| R1 | Broad allow rules: bare `Bash`, `Bash(*)`, `Bash(npx *)`, `Bash(docker exec *)`, `WebFetch`, `mcp____*` | `.claude/settings.json`, tracked `settings.local.json` | Grants any command or fetch without a prompt; runner rules match any inner command | Quote the rule and the documented matching behavior | +| R2 | Deny rules relied on as the only network or delete control | same | Deny matches command text only | Is sandbox network isolation configured? If not, flag the gap | +| R3 | `defaultMode: "bypassPermissions"` or `"auto"` committed to a repository | project settings | Removes or delegates every prompt for every contributor | Report the file:line; note whether the repo targets containers/VMs | +| R4 | Absence of `disableBypassPermissionsMode` where the owner wants it enforced | managed or user settings (owner request only) | The doc calls these keys "most useful in managed settings where they can't be overridden" | Report as observation, not a finding, unless the owner set the policy | +| R5 | Accumulated "don't ask again" rules | `.claude/settings.local.json` | Silent, persistent approvals per repository | List rules; flag network, push, delete, package-run commands | +| R6 | `settings.local.json` committed to git | `git ls-files` | Turns personal approvals into repository-supplied rules | See trust-boundary.md T5 | +| R7 | `additionalDirectories` pointing outside the repository | project settings | Extends file access | Flag home, `~/.ssh`, `~/.claude`, cloud credential dirs | +| R8 | Skill `allowed-tools` in a repository skill | `.claude/skills/*/SKILL.md` | "Workspace trust never gates a skill's `allowed-tools` in any session" (permissions doc) | List tools pre-approved per skill | +| R9 | Sandbox settings and `autoAllowBashIfSandboxed` | settings | Sandbox is the text-independent control | Record whether filesystem and network isolation are on | diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/prompt-injection.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/prompt-injection.md new file mode 100644 index 0000000..1b1a521 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/prompt-injection.md @@ -0,0 +1,50 @@ +--- +name: prompt-injection +description: Paths by which untrusted content reaches an agent's context and instruction files that make the agent obey it +when-to-use: Auditing skills, agents, rules, CLAUDE.md, memory files, hooks and workflows that feed content to an agent +keywords: prompt injection, indirect injection, tool output, WebFetch, issue text, memory poisoning, LLM01, ASI01, ASI06 +priority: critical +related: mcp-trust.md, ci-agents.md, standards-map.md, verification.md +--- + +# Prompt Injection Paths + +## Why it matters + +OWASP LLM01:2026 Prompt Injection: models make "no architectural distinction between +'instructions' and 'data'"; indirect injection arrives through "a web page, a document, an email, +a tool response, a retrieved RAG passage, an image, an MCP server's output, a database row, or an +issue title". With agentic execution "the blast radius extends from the chat surface to whatever +the agent's tools can reach". An attacker can place text through a low-privilege channel ("a +community pull request") and wait for the developer's agent to act on it with the developer's +credentials. +Source: OWASP Top 10 for LLM Applications 2026, PDF linked from https://genai.owasp.org/resource/owasp-genai-llm-top-10-2026/ + +OWASP ASI01 Agent Goal Hijack: agents "cannot reliably distinguish legitimate instructions +from attacker-controlled content", including "deceptive tool outputs, malicious artefacts". +ASI06 Memory & Context Poisoning covers corruption of stored context that "propagates across sessions". +Source: OWASP Top 10 for Agentic Applications 2026, PDF linked from https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/ + +Vendor guidance: "Avoid piping untrusted content directly to Claude"; for most fetches WebFetch +runs a separate model call over the page and Claude receives that answer instead of the raw page. +Source: https://code.claude.com/docs/en/security (section "Protect against prompt injection") + +Permission rules "are enforced by Claude Code, not by the model. Instructions in your prompt or +`CLAUDE.md` shape what Claude tries to do, but they don't change what Claude Code allows." +Source: https://code.claude.com/docs/en/permissions (section "Manage permissions") +Consequence for the audit: an instruction file is never a security control; it is only a surface. + +## Checklist + +| # | Look for | Where | Why | Verify | +|---|----------|-------|-----|--------| +| P1 | Content sources the agent reads unattended: web fetch, issue / PR / comment text, email, tickets, MCP fetch tools | skills, agents, commands, workflows | Indirect injection delivery surfaces (LLM01:2026) | Trace source → agent context → tools available at that point | +| P2 | Instructions telling the model to follow, execute or trust observed content ("do what the page says", "apply the instructions in the issue") | `SKILL.md`, agent `.md`, rules, `CLAUDE.md`, commands | Turns data into instructions (ASI01) | Quote the line; check whether the context also holds write or shell tools | +| P3 | Untrusted text interpolated into a prompt or a `claude -p` argument | hooks, scripts, workflows | Direct pipe of untrusted content, contrary to vendor guidance | Show the variable's origin (PR title, branch name, file content) | +| P4 | Memory, lesson or notes files written from session content and re-read on later sessions | memory dirs, `MEMORY/`, lesson files, hook outputs injected at session start | Cross-session persistence (ASI06) | Who can write the file; is it injected into every session | +| P5 | Hook output injected as context: `hookSpecificOutput.additionalContext`, or plain stdout of `SessionStart` / `UserPromptSubmit` hooks | hook scripts | "The `additionalContext` field passes a string from your hook into Claude's context window" (https://code.claude.com/docs/en/hooks) | Can the hook echo repository, memory or network content verbatim? | +| P6 | Agents holding both untrusted-input tools and high-impact tools (shell, write, push, send) | agent `tools:` lists, `allowed-tools` | Excessive Agency (LLM06:2025 / LLM03:2026) amplifies any injection | List the pair; a read-only agent lowers severity | +| P7 | Hidden or obfuscated text in instruction files: zero-width or bidi Unicode, base64 blobs, HTML comments | all instruction files | Encoding axis named in LLM01:2026 | Grep for non-printing code points and long base64 runs | +| P8 | Mitigations present: sandboxing, network isolation, human approval before write actions | settings, workflows | Sandbox "still applies even if a prompt injection bypasses Claude's decision-making" (permissions doc, "How permissions interact with sandboxing") | Record presence; absence raises severity, never confidence | + +A static read finds a path, not a working exploit: every P-candidate goes through verification.md. diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/secrets.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/secrets.md new file mode 100644 index 0000000..a28d869 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/secrets.md @@ -0,0 +1,53 @@ +--- +name: secrets +description: Secrets stored in agent configuration, hook commands, MCP config and agent memory files +when-to-use: Auditing a repository for API keys and tokens in .claude/, .mcp.json, plugin manifests, hooks, memory or lesson files and committed .env files +keywords: secrets, api key, token, .mcp.json, settings.json, env, memory, LESSON.md, userConfig sensitive, redaction +priority: critical +related: hooks-plugins.md, mcp-trust.md, templates/audit-report.md +--- + +# Secrets in Agent Configuration and Memory + +## Scope statement + +No vendor source read for this skill says to scan `~/.claude` or other user-level agent +directories. Scanning them is this project's own check, run read-only and only when the owner +asks. Inside the audited repository, every file below is in scope. + +## Redaction rule (non-negotiable) + +Never print, quote, hash or partially reveal a secret value. A finding records `file:line`, the +secret TYPE (for example "Anthropic API key", "GitHub token", "bearer token in header") and how +the type was recognised (variable name, header name, key prefix). Evidence lines are rewritten +with the value replaced by `[REDACTED]`. Why: the report itself is committed under +`docs/security/` and would leak the secret a second time. + +## Documented facts + +- Plugin `userConfig` options with `"sensitive": true` go to the platform's secure credential + store; non-sensitive values are saved under `pluginConfigs` in the user's `settings.json`. + Source: https://code.claude.com/docs/en/plugins-reference (section "User configuration") +- `.mcp.json` supports `${VAR}` expansion in `command`, `args`, `env`, `url`, `headers`, so a + shared file can reference a secret instead of embedding it. + Source: https://code.claude.com/docs/en/mcp (section "Environment variable expansion in `.mcp.json`") +- Claude Code stores its own API keys and tokens in the macOS Keychain when available, in a + `0600` file on Linux. + Source: https://code.claude.com/docs/en/security (section "Additional safeguards") +- A project `env` block in settings applies in `-p` and SDK runs without trust. + Source: https://code.claude.com/docs/en/permissions (section "What runs before you trust a folder") + +## Checklist + +| # | Look for | Where | Why | Verify | +|---|----------|-------|-----|--------| +| S1 | Literal keys or tokens | `.claude/settings*.json` (`env`, `apiKeyHelper` command), `.mcp.json` (`env`, `headers`, `args`, `url`) | Committed config is shared with every clone (CWE-798) | Is the value a literal or a `${VAR}` reference? Only literals are findings | +| S2 | Credentials inside hook commands or hook scripts | `hooks/hooks.json`, scripts they call | Hooks run on every installer's machine | Literal token or `Authorization:` header in the script | +| S3 | Secret-like `userConfig` options without `sensitive: true` | `plugin.json` | Value lands in `settings.json` in clear | Option name or description mentions key / token / password / secret | +| S4 | Secrets in memory, lesson, notes or transcript files | `MEMORY/`, `*LESSON*.md`, agent memory dirs, `.claude/` notes | Re-read into every session and often committed | Grep key-like patterns (skill `security-scan` → `references/secrets-patterns.md`); record type and file:line only | +| S5 | Committed `.env` or `.env.*` with real values | repository root and subfolders | Classic leak, often loaded by MCP servers or hooks | `git ls-files \| grep -E '(^\|/)\.env'`; ignore `.env.example` with placeholders | +| S6 | Secrets written to logs by hooks | hook scripts writing log files | CWE-532 | Look for `env` dumps or token variables echoed to files | +| S7 | Credentials in a remote MCP `url` (userinfo `user:pass@`) | `.mcp.json` | Sent to the named server | Report host and type only | + +Before marking S1-S7 confidence 8 or more, confirm the value is not a placeholder (`xxx`, +``, `changeme`, empty) and not a reference (`${VAR}`); see verification.md. diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/standards-map.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/standards-map.md new file mode 100644 index 0000000..11be6cd --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/standards-map.md @@ -0,0 +1,59 @@ +--- +name: standards-map +description: OWASP LLM Top 10 (2025 and 2026), OWASP Top 10 for Agentic Applications 2026 and CWE entries, as read on their sources, mapped to the audit areas +when-to-use: Filling the "standard reference" and "CWE" fields of a finding +keywords: OWASP, LLM01, LLM03, LLM06, ASI01, ASI02, ASI03, ASI04, ASI05, ASI06, CWE +priority: high +related: prompt-injection.md, templates/audit-report.md +--- + +# Standards Map + +Cite an entry with its edition (`LLM01:2025`, `LLM01:2026`, `ASI01`). Numbering changed between +LLM editions: Excessive Agency is LLM06 in 2025 and LLM03 in 2026; Supply Chain is LLM03 in 2025 +and LLM04 in 2026. + +## Sources (read 2026-11-10) + +| Standard | Source | +|----------|--------| +| OWASP Top 10 for LLM Applications 2025 | https://genai.owasp.org/llm-top-10/ | +| OWASP Top 10 for LLM Applications 2026 | PDF linked from https://genai.owasp.org/resource/owasp-genai-llm-top-10-2026/ | +| OWASP Top 10 for Agentic Applications 2026 | PDF linked from https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/ | +| CWE | https://cwe.mitre.org/data/definitions/.html | + +## OWASP entries used by this skill + +| Entry | Title (as read) | Used for | +|-------|-----------------|----------| +| LLM01:2025 / LLM01:2026 | Prompt Injection | prompt-injection.md, ci-agents.md | +| LLM02:2025 / LLM02:2026 | Sensitive Information Disclosure | secrets.md | +| LLM03:2025 / LLM04:2026 | Supply Chain | hooks-plugins.md, mcp-trust.md | +| LLM06:2025 / LLM03:2026 | Excessive Agency | permissions.md, prompt-injection.md P6, ci-agents.md C4 | +| ASI01 | Agent Goal Hijack | prompt-injection.md P1-P3 | +| ASI02 | Tool Misuse and Exploitation | permissions.md, mcp-trust.md M9 | +| ASI03 | Identity and Privilege Abuse | secrets.md, ci-agents.md C4 (API keys, OAuth tokens, delegated sessions) | +| ASI04 | Agentic Supply Chain Vulnerabilities | hooks-plugins.md, mcp-trust.md (the entry names MCP and plug-ins) | +| ASI05 | Unexpected Code Execution (RCE) | trust-boundary.md, hooks-plugins.md | +| ASI06 | Memory & Context Poisoning | prompt-injection.md P4-P5 | + +Agentic entries not used by default (cite only if the finding fits the text): ASI07 Insecure +Inter-Agent Communication, ASI08 Cascading Failures, ASI09 Human-Agent Trust Exploitation, +ASI10 Rogue Agents. + +## CWE entries used by this skill + +| CWE | Title (as read on cwe.mitre.org) | Typical finding | +|-----|----------------------------------|-----------------| +| CWE-94 | Improper Control of Generation of Code ('Code Injection') | Repository config that runs code pre-trust (also the CWE of CVE-2025-59536) | +| CWE-522 | Insufficiently Protected Credentials | Endpoint override that sends credentials (CWE of CVE-2026-21852) | +| CWE-78 | Improper Neutralization of Special Elements used in an OS Command | Hook or workflow interpolating untrusted text into a shell command | +| CWE-77 | Improper Neutralization of Special Elements used in a Command | Same, non-OS command interpreters | +| CWE-798 | Use of Hard-coded Credentials | Literal secrets in settings, `.mcp.json`, hooks | +| CWE-532 | Insertion of Sensitive Information into Log File | Hooks logging tokens | +| CWE-200 | Exposure of Sensitive Information to an Unauthorized Actor | Secrets in memory files, data sent to third-party MCP hosts | +| CWE-829 | Inclusion of Functionality from Untrusted Control Sphere | Unpinned MCP packages, URL bundles, third-party hooks | +| CWE-1104 | Use of Unmaintained Third Party Components | Abandoned MCP server or action | +| CWE-1427 | Improper Neutralization of Input Used for LLM Prompting | Untrusted content placed in an agent prompt | + +When no CWE fits, leave the field empty rather than stretching one. diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/templates/audit-checklist.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/templates/audit-checklist.md new file mode 100644 index 0000000..98e99c7 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/templates/audit-checklist.md @@ -0,0 +1,58 @@ +--- +name: audit-checklist +description: Copy-ready checklist covering the seven agentic audit areas, one line per check id +keywords: checklist, agentic, hooks, mcp, permissions, secrets, ci, prompt injection +--- + +# Agentic Security Audit Checklist + +Copy into the working notes of the audit. Status: `pass`, `candidate` (goes to the refutation +pass), `n/a` (surface absent), `not checked` (state why). Check ids match the reference files. + +``` +## Scope +Repository: {repo} Commit: {sha} Date: {YYYY-MM-DD} +Agent surfaces found: [ ] .claude/ [ ] .mcp.json [ ] .claude-plugin/ [ ] hooks/ + [ ] skills/ [ ] agents/ [ ] CLAUDE.md / rules / memory + [ ] .github/workflows with agents [ ] other agent tool folders: {list} +User-level config read: [ ] no [ ] yes, on owner request: {paths} + +## Trust boundary (trust-boundary.md) +[ ] T1 hooks in project settings [ ] T2 env / ANTHROPIC_BASE_URL override +[ ] T3 apiKeyHelper and helper commands [ ] T4 repository MCP self-approval keys +[ ] T5 tracked settings.local.json / symlinked .claude +[ ] T6 claude -p runs on this repository [ ] T7 other agent tool folders + +## Hook supply chain (hooks-plugins.md) +[ ] H1 hook inventory [ ] H2 network calls [ ] H3 writes outside project +[ ] H4 hardcoded paths [ ] H5 shell interpolation [ ] H6 MCP from URL / unpinned +[ ] H7 non-sensitive secret userConfig [ ] H8 broad allow hooks [ ] H9 repo session hooks + +## MCP trust (mcp-trust.md) +[ ] M1 inventory [ ] M2 publisher [ ] M3 pinning [ ] M4 env and tokens +[ ] M5 remote hosts [ ] M6 headersHelper [ ] M7 tool descriptions +[ ] M8 content-fetching servers [ ] M9 broad MCP allow rules + +## Prompt injection (prompt-injection.md) +[ ] P1 unattended content sources [ ] P2 obey-observed-content instructions +[ ] P3 untrusted text in prompts [ ] P4 persistent memory [ ] P5 hook context output +[ ] P6 untrusted input + high-impact tools [ ] P7 hidden text [ ] P8 mitigations present + +## Permissions (permissions.md) +[ ] R1 broad allow [ ] R2 deny-only controls [ ] R3 bypass / auto default mode +[ ] R4 disable keys (observation) [ ] R5 saved approvals [ ] R6 committed local settings +[ ] R7 additionalDirectories [ ] R8 skill allowed-tools [ ] R9 sandbox + +## Secrets (secrets.md) — never write a value, type + file:line only +[ ] S1 settings / .mcp.json literals [ ] S2 hook credentials [ ] S3 userConfig sensitive +[ ] S4 memory / lesson files [ ] S5 committed .env [ ] S6 logged secrets [ ] S7 URL userinfo + +## CI agents (ci-agents.md) +[ ] C1 inventory [ ] C2 outsider triggers [ ] C3 interpolated event text +[ ] C4 permissions and secrets [ ] C5 -p on PR head config [ ] C6 action pinning +[ ] C7 auto-posted output + +## Candidates → refutation pass (verification.md) +| Check id | file:line | One-line candidate | Confidence before | after | Destination | +|----------|-----------|--------------------|-------------------|-------|-------------| +``` diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/templates/audit-report.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/templates/audit-report.md new file mode 100644 index 0000000..52cc0e1 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/templates/audit-report.md @@ -0,0 +1,70 @@ +--- +name: audit-report +description: Complete report template for an agentic security audit, with the shared finding fields +keywords: report, template, findings, severity, confidence, cwe, owasp, agentic +--- + +# Agentic Security Audit Report Template + +Write to `docs/security/YYYY-MM-DD-.md` inside the audited repository. Never include a +secret value anywhere in the report; use `[REDACTED]` in evidence lines. + +``` +# Agentic Security Audit — {scope} + +**Repository**: {repo} **Commit**: {sha} **Date**: {YYYY-MM-DD} +**Areas covered**: {trust | hooks | mcp | injection | permissions | secrets | ci} +**Areas not covered**: {list + reason} +**User-level config read**: {no | yes, on owner request: paths} +**Mode**: read-only report; no file of the audited project and no setting was changed. + +## Summary + +| Severity | Findings | +|----------|----------| +| CRITICAL | {n} | +| HIGH | {n} | +| MEDIUM | {n} | +| LOW | {n} | +| Needs manual review | {n} | + +## Findings (confidence 8 or more, each survived the refutation pass) + +### {id} — [{SEVERITY}] {title} +- **Confidence**: {8-10}/10 +- **CWE**: {CWE-id: title | none} +- **Standard reference**: {LLM01:2026 Prompt Injection | ASI04 Agentic Supply Chain Vulnerabilities | ...} +- **Location**: `{file}:{line}` +- **Evidence**: `{exact line, secrets replaced by [REDACTED]}` +- **Exploit scenario**: {who controls the input, what runs or leaks, on which session type} +- **Recommendation**: {change for the owner to make; this audit does not apply it} +- **Verification**: reachability {ok}; value {ok | n/a}; current-doc line {quote + URL}; + mitigations {none | list}; trust state {never-trusted | -p | after trust} + +## Needs manual review (confidence below 8) + +| id | Check | Location | Why unconfirmed | What would confirm it | +|----|-------|----------|-----------------|-----------------------| +| {id} | {check id} | `{file}:{line}` | {reason} | {action} | + +## Hardening notes (no severity, no shown attack path) + +- {check id} `{file}:{line}` — {missing hardening and the suggested change} + +## Inventory + +| Surface | Items found | +|---------|-------------| +| Hooks | {event → command, per source file} | +| MCP servers | {name, source, transport, pinned yes/no} | +| Agent / skill files with tools | {file → tools} | +| CI steps running an agent | {workflow → job → step} | + +## Limits + +A static read does not prove that an injection succeeds or that a hook is malicious in intent. +See the "What this skill does not prove" section of the agentic-security skill. +``` + +Finding id format: `AGT-{area}-{nn}` with area one of `TRUST`, `HOOK`, `MCP`, `PI`, `PERM`, +`SEC`, `CI` (for example `AGT-MCP-02`). diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/trust-boundary.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/trust-boundary.md new file mode 100644 index 0000000..30f7b3b --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/trust-boundary.md @@ -0,0 +1,73 @@ +--- +name: trust-boundary +description: Repository files that execute or send credentials before or around the workspace trust dialog +when-to-use: Auditing .claude/settings.json, .mcp.json and settings.local.json of a repository a developer may clone and open +keywords: trust dialog, hooks, env, apiKeyHelper, enableAllProjectMcpServers, ANTHROPIC_BASE_URL, CVE-2025-59536, CVE-2026-21852 +priority: critical +related: hooks-plugins.md, mcp-trust.md, templates/audit-checklist.md +--- + +# Trust Boundary + +## Why it matters + +Check Point Research (2026-02-25) showed that a repository's `.claude/settings.json` is +"just another file in the repository", so any contributor with commit access can ship hooks, +MCP auto-approval and environment overrides that run on every collaborator's machine. +Source: https://research.checkpoint.com/2026/rce-and-api-token-exfiltration-through-claude-code-project-files-cve-2025-59536/ + +| Case (Check Point) | Mechanism | +|--------------------|-----------| +| RCE via project hooks | `SessionStart` hook in `.claude/settings.json` ran after "Yes, proceed" with no further prompt (advisory GHSA-ph6w-f82w-28w6, named in the article) | +| RCE via MCP consent bypass | `enableAllProjectMcpServers` / `enabledMcpjsonServers` in the repository settings started `.mcp.json` commands before the trust dialog was answered | +| API key exfiltration | `ANTHROPIC_BASE_URL` set in project settings; requests carrying the API key left before the trust prompt | + +CVE records, as read: + +| CVE | Record text (abridged) | CWE | Fixed in | +|-----|------------------------|-----|----------| +| CVE-2025-59536 | Code contained in a project could execute before the user accepted the startup trust dialog | CWE-94 | 1.0.111 | +| CVE-2026-21852 | A repository settings file setting `ANTHROPIC_BASE_URL` caused API requests, potentially leaking API keys, before the trust prompt | CWE-522 | 2.0.65 | + +Sources: https://cveawg.mitre.org/api/cve/CVE-2025-59536 and +https://cveawg.mitre.org/api/cve/CVE-2026-21852. Check Point states all reported issues were +patched before publication. These CVEs are fixed; the audit still flags the same +configuration because current documentation lists content that runs without trust (below). + +## What runs before you trust a folder (current documentation) + +Source: https://code.claude.com/docs/en/permissions (section "What runs before you trust a folder"). + +| Repository content | Trusted only a parent folder | `claude -p` or SDK, never trusted | +|--------------------|------------------------------|-----------------------------------| +| Hooks in settings files, the `env` block, helper commands such as `apiKeyHelper`, a project skill's hooks and `allowed-tools` | Used | Used | +| `permissions.allow` and `additionalDirectories` in `.claude/settings.json` | Not used until trust is accepted | Not used (stderr warning) | +| Servers in `.mcp.json`, including ones the repository approves in its own settings | Claude Code asks first; the repository's approvals don't count | Connected without asking, approved or not | +| `headersHelper` on a `.mcp.json` server | Not run until trust | Not run | + +Also documented on the same page: +- A tracked `.claude/settings.local.json`, or a `.claude` that is a symlink, is treated as + repository-supplied and its rules are held until trust. +- `disableAllHooks` set only in user settings is not enough for a `-p` run, "because the + repository's project settings take precedence over yours and can set it back to `false`". +- Hardening for `-p` in an unknown repository: `--setting-sources user`, `--bare`, + `--settings '{"disableAllHooks": true}'`, `disabledMcpjsonServers`. + +Security doc: "A `-p` session shows neither prompt" (trust dialog, `.mcp.json` approval). +Source: https://code.claude.com/docs/en/security (section "Additional safeguards"). + +MCP doc: in an untrusted folder, `enableAllProjectMcpServers` or `enabledMcpjsonServers` +committed to `.claude/settings.json` is ignored and the server stays pending. +Source: https://code.claude.com/docs/en/mcp (section "Project server approvals and workspace trust"). + +## Checklist + +| # | Look for | Where | Verify | +|---|----------|-------|--------| +| T1 | Any `hooks` key | `.claude/settings.json`, tracked `.claude/settings.local.json` | List event, matcher, command; flag network calls, downloads, writes outside the repo | +| T2 | `env` block, especially `ANTHROPIC_BASE_URL` or other endpoint overrides | same files | Compare the host with the vendor endpoint; any third-party host is a finding candidate | +| T3 | `apiKeyHelper` and other helper commands | same files | Read the command; it runs in `-p`/SDK sessions without trust | +| T4 | `enableAllProjectMcpServers`, `enabledMcpjsonServers` | committed settings | Report as repository self-approval; state which session types still honor it | +| T5 | `.claude/settings.local.json` tracked in git, or `.claude` symlinked | `git ls-files .claude`, `ls -la` | Tracked local settings are repository-supplied | +| T6 | Workflows or scripts running `claude -p` on this repository | `.github/workflows/`, `scripts/`, `package.json` scripts | `-p` uses hooks, `env` and `.mcp.json` servers without trust | +| T7 | Equivalent config folders of other agent tools | `.vscode/` and tool-specific folders | Check Point advises inspecting them; apply T1-T3 by analogy and mark tool-specific behavior "to verify" | diff --git a/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/verification.md b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/verification.md new file mode 100644 index 0000000..c34e820 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/agentic-security/references/verification.md @@ -0,0 +1,67 @@ +--- +name: verification +description: Read-only refutation pass every candidate finding must survive, confidence scale, and what a static agentic audit cannot prove +when-to-use: After the checklists, before writing any finding into the report +keywords: verification, false positive, confidence, refutation, limits, needs manual review +priority: critical +related: templates/audit-report.md, templates/audit-checklist.md +--- + +# Verification Pass and Limits + +## Refutation pass (read-only, for every candidate) + +Try to prove the candidate wrong before reporting it. Record each answer in the finding. + +1. **Reachability** — Is the file actually loaded? (Is the plugin enabled by this repository's + settings, is the hook file referenced or at its default location, is the workflow trigger live, + is the server listed for this scope?) Unreferenced or dead config is not a finding. +2. **Value check** — For secrets: literal value, not a `${VAR}` reference, placeholder or + example file. For endpoints: a third-party host, not the vendor or localhost. +3. **Version check** — If the risk depends on Claude Code behavior, quote the current + documentation line that makes it true today. A fixed CVE alone does not make a current finding. +4. **Mitigation check** — Is there a sandbox, network isolation, a deny hook, `--bare` / + `--setting-sources user`, or a maintainer approval gate that neutralises the path? A mitigation + lowers severity; it is recorded, not ignored. +5. **Trust-state check** — Does the risk need a never-trusted folder, a `-p` run, or a user who + already accepted trust? State which; the severity differs. +6. **Independent re-read** — Re-open the exact file:line and confirm the evidence line matches + what the finding says (no paraphrase drift). + +## Confidence scale + +| Score | Meaning | Destination | +|-------|---------|-------------| +| 9-10 | Evidence read at file:line, path reachable, no mitigation found, behavior quoted from current docs | Finding | +| 8 | As above with one assumption stated explicitly (for example a GitHub setting not visible from the repo) | Finding | +| 5-7 | Plausible, but reachability, value or trust state not confirmed | Needs manual review | +| 1-4 | Pattern match only | Needs manual review, or drop with a note | + +Only confidence 8 or more is reported as a finding. + +## Severity guide + +The scale and its definitions are the plugin's `rules/security-rules.md`; this table gives typical +agentic cases for each level. + +| Severity | Typical case | +|----------|--------------| +| CRITICAL | Code execution or credential exfiltration on clone/open or in CI without any human step | +| HIGH | Same impact behind one routine human action (accepting trust, enabling a plugin), or a literal live secret | +| MEDIUM | Prompt-injection path to write or network tools with a partial mitigation; broad allow rules | +| LOW | Shown attack path with minor impact, e.g. non-sensitive `userConfig` with low-value data | + +Hygiene with no shown attack path (for example an unpinned but reputable server) is a hardening +note without severity, not a finding. + +## What this skill does not prove + +- A static read shows that untrusted text can reach the model; it cannot prove the model will + follow it. Injection success depends on the model, its context and the tools it holds; OWASP + LLM01:2026 states there is "no clean equivalent to parameterized queries". +- It does not execute hooks, MCP servers or workflows, and never opens the repository with an + agent to "test" the trust dialog. +- It does not audit the code of third-party MCP servers or actions beyond what is in the repository. +- It cannot see user-level, managed or GitHub-side settings unless the owner provides them. +- Vendor behavior is version-dependent: every documented fact in the references is dated by the + read date of its source, and must be re-checked when the documentation changes. diff --git a/.cursor-plugin/plugins/fuse-security/skills/auth-audit/SKILL.md b/.cursor-plugin/plugins/fuse-security/skills/auth-audit/SKILL.md index 1260450..49d6e2d 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/auth-audit/SKILL.md +++ b/.cursor-plugin/plugins/fuse-security/skills/auth-audit/SKILL.md @@ -1,59 +1,64 @@ --- name: auth-audit -description: "Use when auditing JWT, session, OAuth2/PKCE, password, or MFA implementations for security vulnerabilities and best-practice deviations." -argument-hint: "[--jwt] [--session] [--oauth]" +description: "Use when auditing authentication (JWT, sessions, cookies, OAuth2/OIDC/PKCE, password storage, MFA, account recovery) or authorization (BOLA/IDOR, mass assignment, function-level checks, tenant isolation) in web, API or iOS code." +argument-hint: "[--jwt] [--session] [--oauth] [--authz]" user-invocable: true --- -This skill audits authentication and authorization implementations end to end: JWT signing -algorithm, expiration, refresh, and storage; session storage, expiry, regeneration, and -fixation; OAuth2 PKCE, state parameter, and redirect validation; password hashing algorithm, -strength rules, and reset flow; and MFA implementation, backup codes, and recovery. - -It runs a fixed workflow — detect the auth implementation, scan for known anti-patterns, -verify cryptographic choices, check token/session lifecycle, and audit authorization logic -(RBAC/ABAC) — checking for vulnerabilities such as JWT signed with `none`, undersized JWT -secrets, missing/too-long token expiration, refresh tokens in localStorage, session fixation, -missing CSRF protection, and OAuth flows missing PKCE or the `state` parameter. +This skill audits authentication and authorization end to end and reports findings — it +never modifies the audited project. Authentication: self-contained tokens (JWT), sessions and +cookies, OAuth2/OIDC with PKCE, password storage, MFA and account recovery. Authorization: +object-level (OWASP API1:2023 BOLA/IDOR), property-level (API3:2023, mass assignment and +excessive exposure), function-level (API5:2023) and tenant isolation, with search heuristics +for Next.js route handlers and server actions, TanStack Start server functions, Laravel +policies/gates, and Go/Rust HTTP handlers. Mobile iOS points to OWASP MASVS 2.1.0 +MASVS-AUTH / MASVS-STORAGE. + +Every fixed value (hash parameters, timeouts, PKCE rules) comes from a cited primary source: +OWASP ASVS 5.0.0, OWASP Password Storage Cheat Sheet, RFC 9700, RFC 7518, NIST SP 800-63B-4. # Auth Audit Skill -## Overview - -Comprehensive audit of authentication and authorization implementations. +## Workflow -## Audit Categories +1. **Detect** the auth stack (session framework, JWT library, OAuth/OIDC client or AS, password hasher, MFA) and the entry-point types (route handlers, server actions/functions, controllers, handlers). +2. **Authentication pass** — apply [Auth Patterns](references/auth-patterns.md) section by section. +3. **Authorization pass** — apply the method in [Authorization Patterns](references/authorization-patterns.md) to every entry point that takes an identifier or performs a privileged action. +4. **Checklist** — tick [Auth Checklist](references/templates/auth-checklist.md); every unchecked item is a candidate. +5. **Refute** — run a second, read-only pass on each candidate that tries to disprove it (central middleware, base controller, policy, DB row-level security, query scope, framework default). Keep it only if it survives. +6. **Report** — findings and "needs manual review" list in the audited repository at `docs/security/YYYY-MM-DD-.md`. -| Category | Checks | -|----------|--------| -| JWT | Signing algo, expiration, refresh, storage | -| Sessions | Storage, expiry, regeneration, fixation | -| OAuth2 | PKCE, state param, redirect validation | -| Passwords | Hashing algo, strength rules, reset flow | -| MFA | Implementation, backup codes, recovery | +## Finding format (shared contract) -## Workflow +| Field | Content | +|-------|---------| +| id | `AUTH-NNN` / `AUTHZ-NNN` | +| title | One line | +| severity | CRITICAL / HIGH / MEDIUM / LOW | +| confidence | 1-10 — only ≥ 8 is reported as a finding; lower goes to "needs manual review" | +| CWE | e.g. CWE-639, CWE-915, CWE-347, CWE-384, CWE-916 | +| standard | OWASP Top 10:2025 (A01 Broken Access Control, A07 Authentication Failures, …), OWASP API Security Top 10 2023, OWASP ASVS 5.0.0 (`v5.0.0-x.y.z`), OWASP MASVS 2.1.0 — whichever applies | +| location | file:line (or URL) | +| evidence | The code excerpt or response that shows it (never a secret value — redact) | +| exploit scenario | Concrete steps an attacker takes | +| recommendation | Smallest fix; snippets are recommendations, not applied | -1. **Detect** auth implementation (JWT, sessions, OAuth) -2. **Scan** for known anti-patterns -3. **Verify** cryptographic choices -4. **Check** token/session lifecycle -5. **Audit** authorization logic (RBAC, ABAC) +Search patterns in the references are heuristics: a grep hit alone never reaches confidence 8. -## Common Vulnerabilities +## Common high-impact defects -- JWT signed with `none` algorithm -- JWT secret too short (< 256 bits) -- No token expiration or too long -- Refresh tokens stored in localStorage -- Session fixation after login -- Missing CSRF protection -- OAuth without PKCE for public clients -- Missing `state` parameter in OAuth flow +- Server action / server function / route handler that authenticates but never checks ownership of the ID it receives (API1:2023) +- Raw request body written to the model (`$request->all()`, `data: body`, binding into the DB entity) (API3:2023) +- JWT accepted without signature verification, with `none`, or without `aud`/`exp` checks (ASVS 9.1-9.2) +- Session id not regenerated on login (ASVS 7.2.4); logout that does not invalidate server-side (ASVS 7.4.1) +- OAuth public client without PKCE `S256`; non-exact redirect URI; implicit or password grant (RFC 9700) +- Password hash below OWASP minimums (e.g. scrypt N=2^15 with p=1, bcrypt cost < 10, fast hashes) +- Password reset that bypasses MFA (ASVS 6.4.3); user enumeration in login/reset (ASVS 6.3.8) ## References -- [Auth Patterns](references/auth-patterns.md) +- [Auth Patterns](references/auth-patterns.md) — tokens, sessions, OAuth/OIDC, password storage, MFA, recovery +- [Authorization Patterns](references/authorization-patterns.md) — BOLA/BOPLA/BFLA, tenant isolation, per-stack heuristics, iOS MASVS - [Auth Checklist](references/templates/auth-checklist.md) diff --git a/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/auth-patterns.md b/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/auth-patterns.md index 9886e1c..3ffaaa5 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/auth-patterns.md +++ b/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/auth-patterns.md @@ -1,68 +1,135 @@ --- name: auth-patterns -description: Authentication security patterns for JWT, sessions, OAuth2, and password hashing -when-to-use: When auditing authentication implementations or detecting auth anti-patterns -keywords: jwt, session, oauth, pkce, bcrypt, argon2, authentication +description: Authentication security reference for JWT/self-contained tokens, sessions, OAuth2/OIDC, password storage, MFA and account recovery, with every fixed value tied to its primary source +when-to-use: When auditing authentication implementations or detecting authentication anti-patterns +keywords: jwt, session, oauth, pkce, bcrypt, argon2, scrypt, pbkdf2, mfa, recovery, authentication priority: high -related: templates/auth-checklist.md +related: authorization-patterns.md, templates/auth-checklist.md --- # Authentication Patterns Reference -## JWT (JSON Web Tokens) +Values below were read from the cited primary source on 2026-11-10. A value with no +primary-source number is stated as a risk decision, never invented. Cite the requirement +ID in findings using the ASVS format `v5.0.0-.
.`. CWE tags in the +search lists are the auditor's mapping, not taken from the cited pages — confirm the CWE +entry before reporting. -### Secure Practices -- **Algorithm**: RS256 or ES256 (asymmetric) preferred -- **Secret**: Minimum 256-bit for HS256 -- **Expiration**: Access token 15min, Refresh 7 days -- **Storage**: httpOnly secure cookie (NOT localStorage) -- **Refresh**: Rotate refresh tokens on use -- **Claims**: Minimal payload, no sensitive data +Sources (abbreviations used below): +- **ASVS** — OWASP ASVS 5.0.0, https://github.com/OWASP/ASVS/tree/v5.0.0/5.0/en (V6 Authentication, V7 Session Management, V9 Self-contained Tokens, V10 OAuth and OIDC, V3 Web Frontend) +- **PSCS** — OWASP Password Storage Cheat Sheet, https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html +- **RFC9700** — OAuth 2.0 Security Best Current Practice (Jan 2025), https://www.rfc-editor.org/rfc/rfc9700.html +- **RFC7518** — JSON Web Algorithms, https://www.rfc-editor.org/rfc/rfc7518 (Section 3.2) +- **NIST-B4** — NIST SP 800-63B-4, https://pages.nist.gov/800-63-4/sp800-63b.html -### Anti-Patterns (GREP) -- `algorithm.*none` → Algorithm confusion attack -- `expiresIn.*[0-9]+d` (> 1d) → Too long access token -- `localStorage.*token` → XSS-accessible storage -- `jwt\.sign.*HS256.*short_secret` → Weak secret +## Self-contained tokens (JWT) + +| Check | Requirement | Source | +|-------|-------------|--------| +| Signature/MAC verified before reading claims | Mandatory | ASVS 9.1.1 | +| Algorithm allowlist, never `none`; mixing symmetric + asymmetric needs key-confusion controls | Mandatory | ASVS 9.1.2 | +| `jku` / `x5u` / `jwk` header keys only from an allowlist of trusted sources | Mandatory | ASVS 9.1.3 | +| `exp` and `nbf` verified | Mandatory | ASVS 9.2.1 | +| Token type checked (access token for authz, ID token only for authn) | L2 | ASVS 9.2.2 | +| `aud` validated against an allowlist | L2 | ASVS 9.2.3, 10.3.1 | +| HS256 key length | ≥ 256 bits (key at least the hash output size) | RFC7518 §3.2 | +| Access/refresh token lifetime | No fixed number in ASVS 5.0.0 or RFC 9700. Lifetime is a documented risk decision (ASVS 7.1.1); refresh tokens MUST have an absolute expiration (ASVS 10.4.8) | ASVS 7.1.1, 10.4.8 | +| Logout/revocation of self-contained tokens | Deny-list, per-user "not before" time, or per-user key rotation | ASVS 7.4.1 | +| Browser apps (BFF) | Access and refresh tokens reachable only by the backend | ASVS 10.1.1 | + +Anti-pattern search (heuristics — confirm by reading the verify call site): +- `algorithms?\s*:\s*\[?[^\]]*['"]none['"]` → `none` accepted (CWE-347) +- `jwt\.decode\(` without a matching `jwt\.verify\(` in the same flow → claims read unverified (CWE-347) +- `verify\(.*\{\s*\}\)` or verify options without `algorithms` → no allowlist (library-dependent, verify docs of the library in use) +- `localStorage\.(setItem|getItem)\(.*(token|jwt)` → token readable by any XSS (ASVS 10.1.1 for OAuth tokens; CWE-922) ## Sessions -### Secure Practices -- **Storage**: Server-side (Redis, DB), not client cookies -- **ID**: Cryptographically random, 128+ bits -- **Expiry**: Absolute (24h) + idle (30min) -- **Regeneration**: New ID after login -- **Flags**: httpOnly, secure, SameSite=Lax/Strict - -### Anti-Patterns (GREP) -- `session.*cookie.*httpOnly.*false` → XSS risk -- `session.*secure.*false` → MITM risk -- No `regenerate` after authentication → Fixation - -## OAuth2 / OIDC - -### Secure Practices -- **PKCE**: Required for all public clients (SPA, mobile) -- **State**: Random, verify on callback -- **Redirect**: Exact match, no wildcards -- **Scope**: Minimal permissions requested -- **Token**: Exchange code server-side - -### Anti-Patterns (GREP) -- Missing `code_verifier` → No PKCE -- Missing `state` parameter → CSRF risk -- `redirect_uri.*\*` → Open redirect -- Token in URL fragment → Token leakage - -## Password Hashing - -### Secure Algorithms -- **bcrypt**: Cost factor 12+ (default) -- **Argon2id**: Memory 64MB, iterations 3 -- **scrypt**: N=32768, r=8, p=1 - -### Anti-Patterns (GREP) -- `md5(.*password` → Broken hash -- `sha1(.*password` → Broken hash -- `sha256(.*password` → No salt/iterations -- `password.*=.*plaintext` → No hashing +| Check | Requirement | Source | +|-------|-------------|--------| +| Session token verified by a trusted backend | Mandatory | ASVS 7.2.1 | +| Reference token entropy | ≥ 128 bits, CSPRNG | ASVS 7.2.3 | +| New token on authentication and re-authentication, old one terminated (fixation) | Mandatory | ASVS 7.2.4 | +| Inactivity + absolute timeout | Risk-based and documented (ASVS 7.3.1, 7.3.2). NIST-B4 values: AAL1 overall ≤ 30 days (inactivity optional); AAL2 overall ≤ 24 h, inactivity ≤ 1 h; AAL3 overall ≤ 12 h, inactivity ≤ 15 min | ASVS 7.3, NIST-B4 | +| Logout / expiry really invalidates server-side | Mandatory | ASVS 7.4.1 | +| All sessions terminated on account disable/delete | Mandatory | ASVS 7.4.2 | +| Option to terminate other sessions after any factor change | L2 | ASVS 7.4.3 | +| Re-authentication before changing email, phone, MFA, recovery data | L2 | ASVS 7.5.1 | +| Cookie: `Secure` + `__Host-` or `__Secure-` prefix | L1 (prefix `__Host-` at L2) | ASVS 3.3.1, 3.3.3 | +| Cookie: `HttpOnly` for session tokens; `SameSite` per cookie purpose | L2 | ASVS 3.3.4, 3.3.2 | + +Anti-pattern search (heuristics): +- `httpOnly\s*:\s*false`, `secure\s*:\s*false`, `'http_only'\s*=>\s*false`, `'secure'\s*=>\s*false` → missing cookie flag (CWE-1004, CWE-614) +- Login handler without `regenerate` / `session()->regenerate()` / new session id → fixation (CWE-384). Laravel's built-in auth regenerates; flag only custom login code. +- Hard-coded session timeout constants → compare with the documented AAL target above + +## OAuth 2.0 / OIDC + +| Check | Requirement | Source | +|-------|-------------|--------| +| PKCE for public clients | MUST | RFC9700 §2.1.1 | +| PKCE for confidential clients | RECOMMENDED | RFC9700 §2.1.1 | +| Challenge method | `S256` (SHOULD; it is the only method that does not expose the verifier); AS must reject `plain` | RFC9700 §2.1.1, ASVS 10.4.6 | +| PKCE challenge / OIDC `nonce` / `state` | Transaction-specific, unguessable, bound to the user agent | RFC9700 §2.1.1, ASVS 10.1.2 | +| CSRF on redirect endpoint | PKCE (if AS support confirmed), else one-time `state`, or OIDC `nonce` | RFC9700 §2.1, §4.7.1 | +| Redirect URI matching (AS) | Exact string match (port exception for localhost native apps) | RFC9700 §2.1, ASVS 10.4.1 | +| Open redirectors on client/AS | MUST NOT exist | RFC9700 §2.1 | +| Implicit (`token`) grant | Clients SHOULD NOT use it (RFC 9700); "must no longer be used" (ASVS) | RFC9700 §2.1.2; ASVS 10.4.4 | +| Resource owner password credentials grant | MUST NOT be used | RFC9700 §2.4; ASVS 10.4.4 | +| Access tokens in URL query | MUST NOT | RFC9700 §4.3.2 | +| Refresh tokens of public clients | Sender-constrained (DPoP/mTLS) or rotation with reuse detection | RFC9700 §2.2.2, ASVS 10.4.5 | +| Authorization code | Single use; lifetime ≤ 10 min (L1/L2), ≤ 1 min (L3) | ASVS 10.4.2, 10.4.3 | +| Multiple authorization servers | Mix-up defense (`iss` checked) | RFC9700 §2.1, ASVS 10.2.2 | +| OIDC client | `nonce` checked, `aud == client_id`, user identified by `iss`+`sub` | ASVS 10.5.1, 10.5.4, 10.3.3 | + +Anti-pattern search (heuristics): +- Authorization request built without `code_challenge` → no PKCE +- `code_challenge_method=plain` or `'plain'` → weak PKCE +- `response_type=token` / `grant_type=password` → deprecated grants +- Redirect handler that reads `redirect`, `next`, `returnTo`, `callbackUrl` from the query and redirects without an allowlist → open redirect (CWE-601) +- `redirect_uri` compared with `startsWith`, regex or wildcard → non-exact match + +## Password storage + +Per PSCS: prefer Argon2id; scrypt when Argon2id is unavailable; bcrypt **only** for legacy +systems; PBKDF2 when FIPS-140 is required. Each listed configuration is a **minimum**; +benchmark and go higher if latency allows (PSCS: hashing should take less than one second). + +| Algorithm | Minimum configurations (pick one) | Source | +|-----------|-----------------------------------|--------| +| Argon2id | m=47104 (46 MiB) t=1 p=1 · m=19456 (19 MiB) t=2 p=1 · m=12288 (12 MiB) t=3 p=1 · m=9216 (9 MiB) t=4 p=1 · m=7168 (7 MiB) t=5 p=1 | PSCS | +| scrypt | N=2^17 r=8 p=1 · N=2^16 r=8 p=2 · N=2^15 r=8 p=3 · N=2^14 r=8 p=5 · N=2^13 r=8 p=10 | PSCS | +| bcrypt | Work factor ≥ 10 (as high as the server allows); max input 72 bytes | PSCS | +| PBKDF2 | HMAC-SHA256 600,000 iterations · HMAC-SHA512 220,000 · HMAC-SHA1 1,400,000 (legacy only) | PSCS | + +Password policy (ASVS V6.2): min length 8, 15 strongly recommended (6.2.1); ≥ 64 allowed (6.2.9); +no composition rules (6.2.5); checked against top-3000 list (6.2.4) and breached set at L2 +(6.2.12); no periodic rotation (6.2.10); paste and password managers allowed (6.2.7); no +truncation or case change (6.2.8). + +Anti-pattern search: +- `md5\(`, `sha1\(`, `createHash\(['"](md5|sha1|sha256)['"]\)` near `password` → fast hash (CWE-916) +- bcrypt `rounds`/`cost`/`saltRounds` < 10 → under PSCS minimum +- `scrypt` with `N: 32768` (2^15) and `p: 1` → below PSCS (2^15 requires p=3) +- Password `maxlength` < 64 or regex enforcing character classes → ASVS 6.2.9 / 6.2.5 + +## MFA and account recovery + +| Check | Requirement | Source | +|-------|-------------|--------| +| MFA required | L2 and up | ASVS 6.3.3 | +| OTP / lookup codes usable once | L2 | ASVS 6.5.1 | +| Out-of-band code lifetime ≤ 10 min; TOTP ≤ 30 s | L2 | ASVS 6.5.5 | +| Lookup / OOB codes ≥ 20 bits entropy, CSPRNG | L2 | ASVS 6.5.3, 6.5.4 | +| Lookup secrets < 112 bits stored with a password hash + 32-bit salt | L2 | ASVS 6.5.2 | +| SMS/phone OTP only with validated number + stronger option offered; not at L3 | L2 | ASVS 6.6.1 | +| OOB code brute force rate-limited | L2 | ASVS 6.6.3 | +| Email not used as an authentication factor | L3 | ASVS 6.3.6 | +| Reset flow does not bypass enabled MFA | L2 | ASVS 6.4.3 | +| Lost MFA factor → identity proofing at enrollment level | L2 | ASVS 6.4.4 | +| No password hints / secret questions | L1 | ASVS 6.4.2 | +| No user enumeration via messages, codes or timing (incl. reset, registration) | L3 | ASVS 6.3.8 | +| Credential stuffing / brute force controls documented and implemented, no malicious lockout | L1 | ASVS 6.1.1, 6.3.1 | +| Recovery codes sent by email valid ≤ 24 h; by SMS/voice ≤ 10 min | NIST | NIST-B4 (account recovery) | + +Mobile (iOS) authentication and storage → see the Mobile section of `authorization-patterns.md`. diff --git a/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/authorization-patterns.md b/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/authorization-patterns.md new file mode 100644 index 0000000..dbbe62c --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/authorization-patterns.md @@ -0,0 +1,123 @@ +--- +name: authorization-patterns +description: Authorization audit reference — object-level (BOLA/IDOR), property-level (BOPLA/mass assignment), function-level (BFLA) and tenant isolation, with search heuristics per stack and mobile pointers (MASVS 2.1.0) +when-to-use: When auditing who may access which object, field or function, after authentication is understood +keywords: authorization, bola, idor, bfla, bopla, mass assignment, tenant, policy, gate, server action, server function +priority: high +related: auth-patterns.md, templates/auth-checklist.md +--- + +# Authorization Patterns Reference + +Authentication answers "who is calling"; authorization answers "may this caller do this +action on this object/field". Most critical findings live here. + +## Standards map (read 2026-11-10) + +| Risk | OWASP API Security Top 10 2023 | ASVS 5.0.0 | CWE (from the API Top 10 page) | OWASP Top 10:2025 | +|------|-------------------------------|------------|--------------------------------|-------------------| +| Object-level (BOLA / IDOR) | API1:2023 | 8.2.2 | CWE-285, CWE-639 | A01:2025 Broken Access Control | +| Property-level (BOPLA: excessive exposure + mass assignment) | API3:2023 | 8.2.3, 8.1.2 | CWE-213, CWE-915 | A01:2025 (CWE-213) / A08:2025 (CWE-915) | +| Function-level (BFLA) | API5:2023 | 8.2.1, 8.1.1 | CWE-285 | A01:2025 | +| Tenant isolation | — | 8.4.1 | CWE-639 | A01:2025 | +| Server-side enforcement (not client JS) | — | 8.3.1 | CWE-602 | A06:2025 | + +Sources: https://api-security.owasp.org/editions/2023/en/0x11-t10/ (list) — CWE lists and +quotes come from the per-risk pages `0xa1-broken-object-level-authorization/`, +`0xa3-broken-object-property-level-authorization/`, `0xa5-broken-function-level-authorization/` · +https://github.com/OWASP/ASVS/blob/v5.0.0/5.0/en/0x17-V8-Authorization.md · +https://top10.owasp.org/2025/ (CWE-602 is the auditor's mapping, not from those pages.) + +Key rules from the sources: +- API1: every function that uses a client-supplied ID to access a record must check the caller may perform that action on that record. Comparing the session user ID with an ID parameter "isn't a sufficient solution" on its own. +- API3: return only the properties the caller may read; avoid auto-binding client input to object properties; allow changes only to client-updatable properties. +- API5: deny by default; never infer "admin" from the URL path; check that a method switch (GET → DELETE) does not bypass a check. + +## Method (applies to every stack) + +1. **Inventory entry points** — every route handler, server action, server function, RPC, GraphQL resolver. Each is an independent endpoint (Next.js and TanStack Start docs say so explicitly, see below). +2. **For each entry point that takes an identifier** (path param, query, body, header): locate the data access and check that the query is scoped to the caller (owner, tenant, role) or that a policy is evaluated on the loaded object **before** the action. +3. **For each write**: check the fields written come from an allowlist/schema, not the raw body. +4. **For each read**: check the response is a DTO/allowlist, not the raw record. +5. **For admin/privileged functions**: check an explicit role/permission check in the handler or an enforced wrapper, not only UI hiding or a layout/page guard. +6. **Second pass (refutation)**: before reporting, look for a central guard you may have missed (middleware matcher, base controller, DAL wrapper, DB row-level security, query scope). A finding stays only if no such guard covers the path. + +All patterns below are **heuristics** that locate candidates. None proves a vulnerability +alone; confirmation needs the data-flow read in steps 2-6. + +## Next.js (App Router) + +Source: https://nextjs.org/docs/app/guides/data-security (read 2026-11-10) — Server Actions are +"reachable via a direct POST request"; "A page-level authentication check does not extend to +the Server Actions defined within it"; check ownership "(authorization, not just authentication)". + +Search targets: +- `rg -l "^['\"]use server['\"]"` → list every server action file; in each exported async function, require an auth call **and** an ownership/permission check before the DB call. +- `rg -n "export async function (GET|POST|PUT|PATCH|DELETE)" app/` → route handlers; same check. +- `rg -n "params\b|searchParams\b" app/` near `findUnique|findFirst|update|delete|where:` → IDs from the URL used in queries; flag when the `where` has only `{ id }` and no owner/tenant term and no policy call follows. +- `rg -n "(update|create|upsert)\(\{[^}]*data:\s*(body|input|formData|Object\.fromEntries)"` → mass assignment candidate (API3). +- Return of full records from actions/handlers (`return db.` / `return await prisma.`) → excessive exposure candidate (API3). +- Auth only in `proxy.ts` (formerly `middleware.ts`) → not sufficient alone; the guide lists `proxy.ts` and `route.ts` as high-scrutiny files and requires re-verification inside each action. + +## TanStack Start + +Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions and +`.../guide/middleware` (via Context7, read 2026-11-10) — "Server functions are API endpoints +reachable independently of whichever route renders the calling UI"; "`beforeLoad` is useful +route UX, but it is not the data boundary". + +Search targets: +- `rg -n "createServerFn\("` → for each, require `.middleware([authMiddleware…])` or an in-handler session check, plus an ownership/tenant check on the IDs from `data`. +- Server functions without `.inputValidator(` (or equivalent schema) that pass `data` straight to a DB write → mass assignment candidate. +- Protection only in route `beforeLoad` → not the data boundary (finding if the server function itself is unprotected). +- Server routes (`createFileRoute(...)({ server: { handlers: … } })`) → same checks as route handlers. + +## Laravel + +Source: https://laravel.com/docs/13.x/authorization (read 2026-11-10) — Gates, Policies, +`Gate::authorize`, `$request->user()->can/cannot`, `can` middleware / `->can()` route method, +`#[Authorize]` controller attribute, policy `before` filters. + +Search targets: +- Controllers/actions that load a model by ID or route-model binding and write/return it with **no** `Gate::authorize(`, `->can(`/`->cannot(`, `can:` middleware, `->can(` on the route, or `#[Authorize(` → BOLA candidate. +- Policy methods that always `return true;` or `before()` returning `true` for broad roles → review. +- `Model::where('id', $id)` / `find($request->…)` without owner or tenant scope and without a policy call → BOLA candidate. +- Mass assignment: `protected $guarded = [];`, `Model::unguard(`, `forceFill(`, `->update($request->all())`, `::create($request->all())` → API3 candidate (prefer `$request->validated()` / `->only([...])`). +- Responses returning models directly without API Resources/`$hidden` → excessive exposure candidate. + +## Go (net/http, chi, gin, echo) + +Heuristics: +- `r.PathValue("` (net/http 1.22+), `chi.URLParam(`, `c.Param(` (gin/echo) feeding a query (`QueryRow`, `Exec`, ORM `First`/`Find`/`Where`) whose SQL/filter has no user/tenant column bound from the authenticated context → BOLA candidate. +- `json.NewDecoder(r.Body).Decode(&model)` or `c.Bind(&model)` / `c.ShouldBindJSON(&model)` where `model` is the persisted struct (not a request DTO) followed by save/update → mass assignment candidate. +- Admin routes registered on a router/group without the auth/role middleware used elsewhere → BFLA candidate. + +## Rust (axum, actix-web) + +Heuristics: +- axum `Path(` / actix `web::Path<` extracted IDs used in `sqlx::query!`/`query_as!` or ORM calls without a user/tenant predicate bound from the auth extractor → BOLA candidate. +- `Json(model)` / `web::Json` where `Model` is the DB entity (derives `Deserialize` and is written as-is) → mass assignment candidate. +- Routers where admin routes are merged without the auth `layer`/`wrap` applied to other protected routes → BFLA candidate. + +## Tenant isolation (ASVS 8.4.1) + +- Every multi-tenant query carries the tenant key from the **server-side** session/token, never from the request body/header/subdomain without validation. +- Look for global scopes / RLS policies; if present, verify they cannot be bypassed (`withoutGlobalScope`, raw queries, admin connections). +- Cache keys, file paths and queue jobs include the tenant key. + +## Mobile — iOS (OWASP MASVS 2.1.0) + +Source: https://mas.owasp.org/MASVS/ and https://github.com/OWASP/masvs/tree/v2.1.0/controls (read 2026-11-10). + +| Control | Text (v2.1.0) | What to check | +|---------|---------------|---------------| +| MASVS-AUTH-1 | The app uses secure authentication and authorization protocols and follows the relevant best practices | Enforcement is on the remote endpoint; app uses OAuth/OIDC per `auth-patterns.md` | +| MASVS-AUTH-2 | The app performs local authentication securely according to the platform best practices | Biometric/PIN not a bypassable boolean (MASWE-0020); keys invalidated on new biometric enrollment (MASWE-0022) | +| MASVS-AUTH-3 | The app secures sensitive operations with additional authentication | Step-up for sensitive actions (MASWE-0023) | +| MASVS-STORAGE-1 | The app securely stores sensitive data | Tokens/secrets in the Keychain, not `UserDefaults`/plist/files (MASWE-0001/0002/0003) | +| MASVS-STORAGE-2 | The app prevents leakage of sensitive data | No secrets in logs (MASWE-0005) or backups (MASWE-0006) | + +MASWE titles were read from the mas.owasp.org navigation; open the MASWE page before citing +test details. iOS heuristics: `UserDefaults.standard.set(` with token/password names; +`LAContext().evaluatePolicy(` whose success alone unlocks data without a Keychain item +protected by access control → MASVS-AUTH-2 candidate. diff --git a/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/templates/auth-checklist.md b/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/templates/auth-checklist.md index 98543d8..3a36cee 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/templates/auth-checklist.md +++ b/.cursor-plugin/plugins/fuse-security/skills/auth-audit/references/templates/auth-checklist.md @@ -1,59 +1,75 @@ --- name: auth-checklist -description: Complete security checklist for JWT, sessions, OAuth2, and password implementations -keywords: checklist, jwt, session, oauth, password, security, audit +description: Authentication and authorization audit checklist with ASVS 5.0.0 / OWASP API Security Top 10 2023 / RFC 9700 / OWASP Password Storage references per item +keywords: checklist, jwt, session, oauth, password, mfa, recovery, authorization, bola, security, audit --- -# Authentication Security Checklist - -## JWT Checklist - -- [ ] Algorithm is RS256/ES256 (not HS256 with weak secret) -- [ ] Access token expires in <= 15 minutes -- [ ] Refresh token expires in <= 7 days -- [ ] Tokens stored in httpOnly secure cookies -- [ ] Refresh tokens rotated on use -- [ ] Token blacklist/revocation mechanism exists -- [ ] No sensitive data in JWT payload -- [ ] JWT signature verified on every request - -## Session Checklist - -- [ ] Session ID is cryptographically random -- [ ] Session stored server-side (Redis/DB) -- [ ] Cookie flags: httpOnly, secure, SameSite -- [ ] Session regenerated after authentication -- [ ] Absolute timeout configured (<= 24h) -- [ ] Idle timeout configured (<= 30min) -- [ ] Session destroyed on logout -- [ ] Concurrent session limit enforced - -## OAuth2 Checklist - -- [ ] PKCE implemented for public clients -- [ ] State parameter generated and verified -- [ ] Redirect URIs exact-match validated -- [ ] Authorization code exchanged server-side -- [ ] Minimal scopes requested -- [ ] Token refresh handled properly -- [ ] Error responses don't leak information - -## Password Checklist - -- [ ] Passwords hashed with bcrypt/Argon2id -- [ ] Minimum length 8+ characters enforced -- [ ] Breached password check (HIBP API) -- [ ] Rate limiting on login attempts -- [ ] Account lockout after N failures -- [ ] Secure password reset flow (time-limited token) -- [ ] No password hints or security questions - -## General Auth Checklist - -- [ ] HTTPS enforced on all auth endpoints -- [ ] CSRF protection on forms -- [ ] Brute force protection (rate limiting) -- [ ] Audit logging for auth events -- [ ] MFA available and encouraged -- [ ] Account recovery flow is secure -- [ ] Error messages don't reveal user existence +# Authentication and Authorization Checklist + +Each item cites its source; values and rationale live in `../auth-patterns.md` and +`../authorization-patterns.md`. A failed item becomes a finding only after the confidence and +refutation rules in `SKILL.md`. + +## Self-contained tokens (JWT) + +- [ ] Signature/MAC verified before any claim is used (ASVS 9.1.1) +- [ ] Algorithm allowlist, `none` rejected (ASVS 9.1.2) +- [ ] `jku`/`x5u`/`jwk` restricted to trusted sources (ASVS 9.1.3) +- [ ] `exp`/`nbf` checked (ASVS 9.2.1); `aud` checked (ASVS 9.2.3) +- [ ] HS256 key ≥ 256 bits (RFC 7518 §3.2) +- [ ] Token lifetimes documented as a risk decision (ASVS 7.1.1); refresh tokens have an absolute expiry (ASVS 10.4.8) +- [ ] Logout/revocation effective for self-contained tokens (ASVS 7.4.1) +- [ ] Browser apps: tokens only reachable by the backend (ASVS 10.1.1) + +## Sessions and cookies + +- [ ] Reference session token ≥ 128 bits from a CSPRNG (ASVS 7.2.3) +- [ ] New session token on login and re-authentication (ASVS 7.2.4) +- [ ] Inactivity and absolute timeouts documented and enforced (ASVS 7.3.1, 7.3.2); compare with NIST SP 800-63B-4 per AAL (AAL2: ≤ 24 h overall, ≤ 1 h inactivity) +- [ ] Logout invalidates server-side (ASVS 7.4.1); disabled account → all sessions ended (ASVS 7.4.2) +- [ ] Re-authentication before changing email/phone/MFA/recovery data (ASVS 7.5.1) +- [ ] Cookies `Secure` + `__Host-`/`__Secure-` prefix (ASVS 3.3.1, 3.3.3), `HttpOnly` for session tokens (ASVS 3.3.4), `SameSite` per purpose (ASVS 3.3.2) +- [ ] Cross-site request forgery defended (ASVS 3.5.1-3.5.3) + +## OAuth 2.0 / OIDC + +- [ ] PKCE with `S256` for public clients (RFC 9700 §2.1.1); AS rejects `plain` (ASVS 10.4.6) +- [ ] `state`/`nonce`/PKCE values transaction-bound (ASVS 10.1.2) +- [ ] Redirect URIs exact-match (RFC 9700 §2.1, ASVS 10.4.1); no open redirector (RFC 9700 §2.1) +- [ ] No implicit or password grant (ASVS 10.4.4) +- [ ] No access token in URL query (RFC 9700 §4.3.2) +- [ ] Public-client refresh tokens sender-constrained or rotated with reuse detection (RFC 9700 §2.2.2, ASVS 10.4.5) +- [ ] Mix-up defense when several authorization servers are used (ASVS 10.2.2) +- [ ] OIDC: `nonce`, `aud == client_id`, user keyed on `iss`+`sub` (ASVS 10.5.1, 10.5.4, 10.3.3) + +## Passwords + +- [ ] Argon2id / scrypt / bcrypt (legacy) / PBKDF2 (FIPS) at or above OWASP Password Storage minimums +- [ ] Min length 8 (15 recommended), ≥ 64 allowed, no composition rules (ASVS 6.2.1, 6.2.9, 6.2.5) +- [ ] Top-3000 and breached-password checks (ASVS 6.2.4, 6.2.12) +- [ ] No forced periodic rotation (ASVS 6.2.10) +- [ ] Credential stuffing / brute-force controls without malicious lockout (ASVS 6.1.1, 6.3.1) +- [ ] No hints or secret questions (ASVS 6.4.2) + +## MFA and recovery + +- [ ] MFA required at L2+ (ASVS 6.3.3) +- [ ] OTP/lookup codes single-use (ASVS 6.5.1); OOB ≤ 10 min, TOTP ≤ 30 s (ASVS 6.5.5) +- [ ] SMS OTP only with a stronger alternative offered (ASVS 6.6.1); OOB codes rate-limited (ASVS 6.6.3) +- [ ] Password reset does not bypass MFA (ASVS 6.4.3); lost factor → re-proofing (ASVS 6.4.4) +- [ ] No user enumeration in login, reset, registration (ASVS 6.3.8) +- [ ] Users notified after credential changes (ASVS 6.3.7) + +## Authorization + +- [ ] Every ID-taking entry point checks object ownership/permission (API1:2023, ASVS 8.2.2) +- [ ] Writes use a field allowlist; reads return DTOs (API3:2023, ASVS 8.2.3) +- [ ] Privileged functions deny by default with explicit role checks (API5:2023, ASVS 8.2.1) +- [ ] Enforcement server-side, not in client code or route guards only (ASVS 8.3.1) +- [ ] Tenant key from server-side identity on every query (ASVS 8.4.1) +- [ ] Next.js server actions / TanStack Start server functions re-check auth and ownership inside each one + +## Mobile (iOS, MASVS 2.1.0) + +- [ ] MASVS-AUTH-1/2/3 — remote enforcement, platform-correct local auth, step-up for sensitive ops +- [ ] MASVS-STORAGE-1/2 — secrets in the Keychain, no leakage to logs/backups diff --git a/.cursor-plugin/plugins/fuse-security/skills/cve-research/SKILL.md b/.cursor-plugin/plugins/fuse-security/skills/cve-research/SKILL.md index c5dafe9..935169d 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/cve-research/SKILL.md +++ b/.cursor-plugin/plugins/fuse-security/skills/cve-research/SKILL.md @@ -1,66 +1,72 @@ --- name: cve-research -description: "Use when checking a specific dependency or package version for known CVEs and security advisories." -argument-hint: " [version]" +description: "Use when checking a specific dependency or package version for known CVEs and security advisories (OSV, GitHub Advisory, NVD), with CVSS, CWE and reachability verification before anything is reported as a finding." +argument-hint: " [version] [ecosystem]" user-invocable: true --- -This skill researches known vulnerabilities for a specific dependency across multiple -sources: OSV.dev (npm, PyPI, Go, crates, Maven), NVD (CVSS scoring), GitHub Advisory -Database (maintainer responses), and Exa web search for advisories not yet indexed. - -It queries OSV.dev first for speed and accuracy, cross-checks NVD for CVSS scoring, uses Exa -for recent advisories, and checks GitHub Advisory for maintainer responses, then -cross-references findings and prioritizes by CVSS score and exploitability — CRITICAL -(9.0-10.0) fixed immediately, HIGH (7.0-8.9) before merge, MEDIUM (4.0-6.9) planned, LOW -(0.1-3.9) documented — reporting fix versions and workarounds. - -Out of scope: this is a single-dependency lookup, not a full project dependency sweep (use -dependency-audit for that). +This skill researches known vulnerabilities for one dependency at the version actually +installed, across OSV.dev, the GitHub Advisory Database and NVD, then a web search for +advisories not yet indexed. Each candidate is scored (CVSS vector + score + CVSS version + +scoring source, CWE) and must pass two mandatory checks before it becomes a finding: the +affected version is the one installed, and the vulnerable code is reachable from the project. + +It reports; it never upgrades the dependency. Out of scope: a full project dependency sweep +(use dependency-audit). # CVE Research Skill -## Overview +## Data sources (query in this order) -Research known vulnerabilities for project dependencies using multiple sources. +| Order | Source | Endpoint | Strength | +|-------|--------|----------|----------| +| 1 | OSV.dev | `api.osv.dev/v1` | Package + version matching, aliases (GHSA, CVE, RUSTSEC, GO, PYSEC) | +| 2 | GitHub Advisory | `api.github.com/advisories` | Reviewed ranges, first patched version, CVSS v3/v4, CWE, EPSS, malware type | +| 3 | NVD | `services.nvd.nist.gov/rest/json/cves/2.0` | NVD and CNA CVSS metrics, CWE, CISA KEV fields | +| 4 | Web search | fuse-browser `browser_fetch` / Exa when available | Advisories not yet indexed, maintainer notes | -## Data Sources - -| Source | API | Coverage | -|--------|-----|----------| -| NVD | nvd.nist.gov/vuln/api | All CVEs | -| OSV.dev | api.osv.dev | npm, PyPI, Go, crates, Maven | -| GitHub Advisory | github.com/advisories | npm, pip, composer, cargo | -| Exa Search | Via MCP | Real-time web search | +Endpoints, bodies and rate limits: [CVE APIs Reference](references/cve-apis.md). +Ready-to-run requests: [Query Templates](references/templates/cve-query.md). ## Workflow -1. **Extract** dependencies from project (package.json, etc.) -2. **Query** each source for known CVEs -3. **Cross-reference** findings across sources -4. **Prioritize** by CVSS score and exploitability -5. **Report** with fix versions and workarounds +1. **Resolve the installed version** from the lockfile (not the manifest range). +2. **Query** OSV (`/v1/query` with ecosystem + name + version), collect IDs and aliases. +3. **Enrich** each ID: GitHub Advisory (CVSS, CWE, patched version), NVD (CVSS by source, KEV). +4. **Search** the web for the package name plus the current year, computed at run time + (`date +%Y`), never a year written in this skill. +5. **Score**: CVSS vector + base score, the CVSS version, and who scored it; CWE id. +6. **Verify (mandatory)** — [Severity and Reachability](references/severity-and-reachability.md): + version check, reachability check, refutation pass. Confidence 1-10; only ≥ 8 is a finding. +7. **Report** with fix version or workaround as an option for the owner. + +## CVSS bands (FIRST qualitative scale, CVSS v3.x and v4.0) + +The band is an input. The reported severity follows the plugin's single scale in +`rules/security-rules.md`, decided after the reachability check. -## Query Strategy +| CVSS base score | Band | +|-----------------|----------| +| 9.0 - 10.0 | CRITICAL | +| 7.0 - 8.9 | HIGH | +| 4.0 - 6.9 | MEDIUM | +| 0.1 - 3.9 | LOW | -For each dependency: -1. Search OSV.dev first (fastest, most accurate for packages) -2. Cross-check NVD for CVSS scoring -3. Use Exa for recent advisories not yet in databases -4. Check GitHub Advisory for maintainer responses +When sources disagree (e.g. NVD scores v3.1 HIGH while the CNA scores v4.0 CRITICAL), report +both with their source and use the highest for ordering. A CVE listed in CISA KEV +(`cisaExploitAdd` in the NVD record) is noted as exploited in the wild. -## Severity Mapping +## Output per finding -| CVSS Score | Severity | Action | -|------------|----------|--------| -| 9.0 - 10.0 | CRITICAL | Fix immediately | -| 7.0 - 8.9 | HIGH | Fix before merge | -| 4.0 - 6.9 | MEDIUM | Plan fix | -| 0.1 - 3.9 | LOW | Document | +id (GHSA/CVE + aliases), title, severity, confidence 1-10, CWE, standard reference +(OWASP Top 10:2025 A03 Software Supply Chain Failures for a vulnerable dependency), package@version, +evidence (advisory, affected range, installed version, reachability), exploit scenario, +recommendation (fixed version / workaround). ## References - [CVE APIs Reference](references/cve-apis.md) +- [Severity and Reachability](references/severity-and-reachability.md) - [Query Templates](references/templates/cve-query.md) diff --git a/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/cve-apis.md b/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/cve-apis.md index 69b4826..8a55419 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/cve-apis.md +++ b/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/cve-apis.md @@ -1,49 +1,75 @@ --- name: cve-apis -description: API references for NVD, OSV.dev, GitHub Advisory, and Exa CVE search -when-to-use: When querying vulnerability databases for known CVEs -keywords: nvd, osv, github-advisory, cve, api, vulnerability +description: Verified endpoints, request shapes, rate limits and severity fields for OSV.dev, GitHub Advisory Database and NVD CVE API 2.0 +when-to-use: When querying vulnerability databases for a package version or a CVE/GHSA id +keywords: nvd, osv, github-advisory, cve, ghsa, cvss, cwe, api, rate-limit priority: high -related: templates/cve-query.md +related: severity-and-reachability.md, templates/cve-query.md --- # CVE API References -## NVD API v2 +## OSV.dev -- **Base URL**: `https://services.nvd.nist.gov/rest/json/cves/2.0` -- **Search by keyword**: `?keywordSearch={package_name}` -- **Search by CPE**: `?cpeName=cpe:2.3:a:{vendor}:{product}:{version}` -- **Rate limit**: 5 requests/30s (no key), 50/30s (with key) -- **Response**: JSON with CVE items, CVSS scores, references +Docs: https://google.github.io/osv.dev/api/ -## OSV.dev API +| Request | Endpoint | +|---------|----------| +| One package/version | `POST https://api.osv.dev/v1/query` | +| Many packages | `POST https://api.osv.dev/v1/querybatch` (returns IDs + `modified` only) | +| Full record | `GET https://api.osv.dev/v1/vulns/{id}` | -- **Base URL**: `https://api.osv.dev/v1` -- **Query endpoint**: `POST /v1/query` -- **Batch query**: `POST /v1/querybatch` -- **Body**: `{"package":{"name":"lodash","ecosystem":"npm"}}` -- **With version**: `{"version":"4.17.20","package":{...}}` -- **Response**: Vulnerability records with affected ranges +- Body: `{"package": {"name": "...", "ecosystem": "..."}, "version": "..."}` or + `{"package": {"purl": "pkg:npm/lodash@4.17.20"}}`. Version in both places → 400. +- Values are case-sensitive. Ecosystem names used by the owner's stacks: `npm`, `Packagist`, + `crates.io`, `Go`, `SwiftURL` (name = Git URL of the package), `PyPI`, `RubyGems`. Full list: + https://ossf.github.io/osv-schema/#affectedpackage-field +- Rate limit: none currently (docs). Pagination via `next_page_token`. +- Severity: `severity[].type` is `CVSS_V2`, `CVSS_V3` or `CVSS_V4` and `severity[].score` is the + **vector string**, not a number — take the numeric score from GitHub/NVD or compute it. + `aliases` links GHSA / CVE ids. CWE is not a top-level OSV field: take it from GitHub + Advisory or NVD. -## GitHub Advisory Database +## GitHub Advisory Database (global advisories REST) -- **GraphQL**: `https://api.github.com/graphql` -- **REST**: `https://api.github.com/advisories` -- **Filter by ecosystem**: `?ecosystem=npm` -- **Filter by severity**: `?severity=critical,high` -- **Auth**: Bearer token required +Docs: https://docs.github.com/en/rest/security-advisories/global-advisories -## Exa Search Queries +- `GET https://api.github.com/advisories` — filters: `ghsa_id`, `cve_id`, `ecosystem` + (`npm`, `composer`, `rust`, `go`, `swift`, `pip`, `rubygems`, `actions`, …), `severity` + (one of `low`, `medium`, `high`, `critical`, `unknown`), `affects` (`package` or + `package@version`), `type` (`reviewed` default, `malware`, `unreviewed`), `cwes`. +- `GET https://api.github.com/advisories/{ghsa_id}` for one record. +- Headers: `Accept: application/vnd.github+json`; `Authorization: Bearer ` optional for + public data but raises the limit. +- Rate limit: 60 requests/hour unauthenticated, 5,000/hour with a personal token + (https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api). +- Useful fields: `vulnerabilities[].vulnerable_version_range`, `first_patched_version`, + `vulnerable_functions`, `cvss_severities.cvss_v3|cvss_v4.{vector_string,score}`, + `cwes[].cwe_id`, `epss`. -Use MCP `web_search_exa` with targeted queries: -- `"{package_name}" CVE vulnerability 2025 2026` -- `"{package_name}" security advisory` -- `"{package_name}" {version} exploit` +## NVD CVE API 2.0 -## Priority Order +Docs: https://nvd.nist.gov/developers/vulnerabilities and https://nvd.nist.gov/developers/start-here -1. **OSV.dev** - Best for package-specific lookups -2. **GitHub Advisory** - Maintainer-verified fixes -3. **NVD** - Authoritative CVSS scores -4. **Exa** - Latest unindexed advisories +- Base URL: `https://services.nvd.nist.gov/rest/json/cves/2.0` (GET only). +- Parameters used here: `cveIds=CVE-…,CVE-…` (comma list; the single `cveId` is marked + deprecated in the docs), `keywordSearch=…`, `resultsPerPage`, `startIndex`. +- API key: header `apiKey: ` (never in the URL, never in a report). +- Rate limit: 5 requests per rolling 30 s without a key, 50 with a key; sleep a few seconds + between requests. +- Severity: `metrics.cvssMetricV40[]`, `metrics.cvssMetricV31[]` (older records may carry other + CVSS versions) — each entry has `source`, `type` (e.g. `Primary` from `nvd@nist.gov`, + `Secondary` from the CNA) and + `cvssData.{version,vectorString,baseScore,baseSeverity}`. CWE: `weaknesses[].description[].value`. + Exploited in the wild: `cisaExploitAdd`, `cisaRequiredAction` (CISA KEV). +- Required notice when displaying NVD data: "This product uses data from the NVD API but is not + endorsed or certified by the NVD." + +## Web search + +Exa (`web_search_exa`) may be unavailable; fall back to fuse-browser `browser_fetch` on the +package's GitHub security advisories page, changelog or release notes. Query patterns, with +`{year}` = current year from `date +%Y` at run time: + +- `"{package_name}" CVE {year}` +- `"{package_name}" {version} security advisory` diff --git a/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/severity-and-reachability.md b/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/severity-and-reachability.md new file mode 100644 index 0000000..9f592c7 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/severity-and-reachability.md @@ -0,0 +1,61 @@ +--- +name: severity-and-reachability +description: How to score a CVE (CVSS vector, score, version, source, CWE) and the mandatory installed-version and reachability checks before a CVE becomes a finding +when-to-use: Before reporting any CVE or advisory as a finding, in cve-research or dependency-audit +keywords: cvss, cvss-v4, cwe, reachability, installed-version, confidence, refutation, kev, epss +priority: high +related: cve-apis.md, templates/cve-query.md +--- + +# Severity and Reachability + +## 1. Severity record + +For every advisory, record all of: + +| Field | Where it comes from | +|-------|--------------------| +| CVSS version | `cvssData.version` (NVD), `cvss_v3` / `cvss_v4` key (GitHub), `CVSS_V3` / `CVSS_V4` type (OSV) | +| Vector | full string, e.g. `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H` | +| Base score | NVD `baseScore` or GitHub `score` (OSV gives only the vector) | +| Scoring source | NVD (`nvd@nist.gov`), the CNA, or GitHub | +| CWE | GitHub `cwes[].cwe_id` or NVD `weaknesses[].description[].value` | +| Exploitation signals | NVD `cisaExploitAdd` (CISA KEV), GitHub `epss` | + +The CVSS band below is an input, not the final severity: the reported severity follows the +plugin's single scale in `rules/security-rules.md`, set after the reachability check (section 3). + +CVSS band from the base score with the FIRST qualitative scale (same bands for v3.x and +v4.0, https://www.first.org/cvss/v4.0/specification-document): 9.0-10.0 CRITICAL, 7.0-8.9 +HIGH, 4.0-6.9 MEDIUM, 0.1-3.9 LOW. Never compare a v3.1 score with a v4.0 score as if they +were the same metric: show both, with their source. + +Example of disagreement (CVE-2026-33634): NVD scored CVSS 3.1 8.8 HIGH; the GitHub CNA scored +CVSS 4.0 9.4 CRITICAL; the record is also in CISA KEV. + +## 2. Mandatory check A — the affected version is installed + +1. Read the resolved version from the lockfile (`bun.lock`, `package-lock.json`, + `pnpm-lock.yaml`, `yarn.lock`, `composer.lock`, `Cargo.lock`, `go.sum`/`go.mod`, + `Package.resolved`), not the manifest range. +2. Compare it with the advisory's affected range (`vulnerable_version_range`, OSV `ranges` / + `versions`). Several copies may be installed: check each path. +3. Not in range → drop it. Range unparseable or no lockfile → "needs manual review". + +## 3. Mandatory check B — the vulnerable code is reachable + +1. Find the vulnerable function / module / feature: GitHub `vulnerable_functions`, the + advisory text, the fix commit. +2. Search the project for imports and calls of it (grep the package import, then the symbol). + For Go, govulncheck's call stacks are the evidence; `cargo audit` and the JS/PHP tools do not + check reachability. +3. Consider configuration: optional feature flags, server-only vs client bundle, dev-only + dependency (build tooling can still be an attack path in CI). +4. Not reachable, or cannot be determined → confidence below 8 → "needs manual review". + +## 4. Confidence and refutation pass + +- Confidence 1-10 reflects checks A and B plus exploit preconditions. Only ≥ 8 is a finding. +- Before reporting, run a second, read-only pass whose goal is to disprove the finding + (withdrawn advisory, patched backport, different package with the same name, unreachable + path, mitigating config). Record what was checked in the finding's evidence. diff --git a/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/templates/cve-query.md b/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/templates/cve-query.md index d9aeeb4..296aa46 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/templates/cve-query.md +++ b/.cursor-plugin/plugins/fuse-security/skills/cve-research/references/templates/cve-query.md @@ -1,60 +1,67 @@ --- name: cve-query -description: Complete query templates for OSV.dev, NVD, GitHub Advisory, and Exa -keywords: query, osv, nvd, github, graphql, template +description: Ready-to-run read-only queries for OSV.dev, GitHub Advisory REST and NVD CVE API 2.0, plus web search patterns with the year computed at run time +keywords: query, osv, nvd, github, advisory, curl, template --- # CVE Query Templates -## OSV.dev Query +All requests are read-only GETs or OSV query POSTs. Never put a token or API key in a URL or +in a report; pass it in a header from an environment variable. -```json -{ - "package": { - "name": "{package_name}", - "ecosystem": "{ecosystem}" - }, - "version": "{version}" -} +## OSV.dev — one package at the installed version + +```bash +curl -s -d '{"package":{"name":"{package_name}","ecosystem":"{ecosystem}"},"version":"{version}"}' \ + https://api.osv.dev/v1/query ``` -Ecosystems: `npm`, `PyPI`, `Go`, `crates.io`, `Packagist`, `Maven`, `NuGet` +Ecosystem values (case-sensitive): `npm`, `Packagist`, `crates.io`, `Go`, `SwiftURL`, `PyPI`, +`RubyGems`. For SwiftPM, `name` is the package's Git URL and `version` its resolved tag. -## NVD Search +## OSV.dev — many packages, then details +```bash +curl -s -d '{"queries":[{"package":{"purl":"pkg:npm/{name}@{version}"}}, + {"package":{"ecosystem":"Packagist","name":"{vendor}/{name}"},"version":"{version}"}]}' \ + https://api.osv.dev/v1/querybatch +curl -s https://api.osv.dev/v1/vulns/{id} # full record for each returned id ``` -GET /rest/json/cves/2.0?keywordSearch={package}&resultsPerPage=20 -``` -## GitHub Advisory GraphQL - -```graphql -{ - securityAdvisories( - first: 10 - orderBy: {field: PUBLISHED_AT, direction: DESC} - classifications: [GENERAL, MALWARE] - ) { - nodes { - ghsaId - summary - severity - publishedAt - vulnerabilities(first: 5) { - nodes { - package { name ecosystem } - vulnerableVersionRange - firstPatchedVersion { identifier } - } - } - } - } -} +## GitHub Advisory Database (REST) + +```bash +curl -s -H "Accept: application/vnd.github+json" \ + ${GITHUB_TOKEN:+-H "Authorization: Bearer $GITHUB_TOKEN"} \ + "https://api.github.com/advisories?ecosystem={gh_ecosystem}&affects={package}@{version}" +curl -s -H "Accept: application/vnd.github+json" https://api.github.com/advisories/{ghsa_id} ``` -## Exa Search Template +`{gh_ecosystem}`: `npm`, `composer`, `rust`, `go`, `swift`, `pip`, `rubygems`, `actions`. +Malware records: add `&type=malware`. Read `cvss_severities`, `cwes`, `first_patched_version`, +`vulnerable_functions`, `withdrawn_at`. +## NVD CVE API 2.0 + +```bash +curl -s ${NVD_API_KEY:+-H "apiKey: $NVD_API_KEY"} \ + "https://services.nvd.nist.gov/rest/json/cves/2.0?cveIds={cve_id},{cve_id_2}" +curl -s ${NVD_API_KEY:+-H "apiKey: $NVD_API_KEY"} \ + "https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch={package}&resultsPerPage=20" ``` -Query: "{package_name} CVE vulnerability {year}" -Focus: Security advisories and patch notes + +Respect 5 requests / 30 s without a key (50 with a key). Prefer `cveIds` lookups of the +aliases OSV returned over `keywordSearch`, which matches description text and is noisy. + +## Web search + +```bash +year=$(date +%Y) # current year at run time; never hardcode a year ``` + +- `"{package_name}" CVE $year` +- `"{package_name}" {version} security advisory` +- `"{package_name}" {version} exploit` + +Use Exa `web_search_exa` when available, otherwise fuse-browser `browser_fetch` on the +package's repository security advisories page and changelog. diff --git a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/SKILL.md b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/SKILL.md index 74c9157..3de445d 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/SKILL.md +++ b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/SKILL.md @@ -1,61 +1,89 @@ --- name: dependency-audit -description: "Use when running ecosystem-specific vulnerability scans across project dependencies (npm/composer/pip/cargo/go/etc), with optional auto-fix." -argument-hint: "[--fix] [ecosystem]" +description: "Use when auditing a project's dependency tree for known vulnerabilities and supply-chain risks (bun/npm/pnpm/yarn, Composer, Cargo, Go modules, SwiftPM, pip, Bundler) and its GitHub Actions workflows. Read-only: reports findings, lists fix commands as options, never applies them." +argument-hint: "[ecosystem]" user-invocable: true --- -This skill runs native package-manager audit tools across a project's full dependency tree, -detecting the package manager from lock files and running the matching command: -npm/yarn/pnpm/bun audit, composer audit, pip-audit/safety scan, cargo audit, govulncheck, -osv-scanner (multi-ecosystem lockfiles), or bundle audit. CocoaPods/SwiftPM have no native -audit command: check Podfile.lock / Package.resolved against OSV.dev or GitHub Advisory. - -It parses each tool's output, classifies findings by severity (CRITICAL/HIGH/MEDIUM/LOW), -and suggests fix versions or alternatives. With the --fix flag it applies safe auto-fixes -where supported (npm audit fix, bun audit fix, cargo audit fix) and gives manual guidance -for ecosystems without auto-fix. - -Out of scope: researching a single named dependency's CVE history in depth belongs to -cve-research. +This skill audits a project's dependencies with each ecosystem's native audit tool (detected +from lockfiles), adds supply-chain checks (OWASP Top 10:2025 A03 Software Supply Chain +Failures) and GitHub Actions workflow checks, and writes one report. It is read-only: it never +installs a tool, never runs a fix command, never edits a lockfile. Fix commands are listed in +the report as options for the owner. + +Out of scope: deep CVE history of one named package (use cve-research). # Dependency Audit Skill -## Overview +## Ground rules -Run dependency vulnerability checks using native package manager audit tools. +1. **Report, never fix.** Every `fix` / `--fix` / `--apply-fixes` command rewrites lockfiles, + manifests or `node_modules`. The audit lists it as an option; it never runs it. +2. **Tool presence first.** Before any command: `command -v `. Missing tool → record + `not run: absent` in the report. Never install it, never skip it silently. +3. **Untrusted projects.** Some tools execute project code (Cargo build scripts, package + manager lifecycle scripts, osv-scanner `fix`). Use the read-only form documented in + `references/audit-commands-systems.md` and never run install commands. +4. **Versions age.** Check a tool's version with its own `--version` rather than trusting a + number written in this skill. -## Supported Ecosystems +## Ecosystems -| Ecosystem | Tool | Auto-fix | -|-----------|------|----------| -| npm/yarn/pnpm/bun | `npm audit` / `yarn npm audit` (Yarn 2+) / `pnpm audit` / `bun audit` | Yes (npm, bun) | -| PHP/Composer | `composer audit` | Manual | -| Python/pip | `pip-audit` / `safety scan` | Manual | -| Rust/Cargo | `cargo audit` | Yes (`fix` feature) | -| Go | `govulncheck ./...` | Manual | -| Swift/CocoaPods/SwiftPM | No native audit — OSV.dev / GitHub Advisory lookup | Manual | -| Ruby/Bundler | `bundle audit` | Manual | -| Any lockfile | `osv-scanner scan source -r .` | Manual | +| Lockfile | Native tool | Reference | +|----------|-------------|-----------| +| `bun.lock` | `bun audit` | [JS and PHP commands](references/audit-commands.md) | +| `package-lock.json` / `npm-shrinkwrap.json` | `npm audit` | same | +| `pnpm-lock.yaml` | `pnpm audit` | same | +| `yarn.lock` (Yarn 2+) | `yarn npm audit` | same | +| `yarn.lock` (Yarn 1 classic) | `yarn audit` | same | +| `composer.lock` | `composer audit` | same | +| `Cargo.lock` | `cargo audit` | [Rust, Go, Swift, Python, Ruby](references/audit-commands-systems.md) | +| `go.mod` / `go.sum` | `govulncheck` | same | +| `Package.resolved` (SwiftPM) | none native — OSV / GitHub Advisory lookup | same | +| `requirements.txt`, `pyproject.toml`, `pylock.*.toml` | `pip-audit` | same | +| `Gemfile.lock` | `bundle-audit` | same | +| any supported lockfile | `osv-scanner` (optional cross-check) | same | ## Workflow -1. **Detect** package manager from lock files -2. **Run** appropriate audit command -3. **Parse** output for vulnerabilities -4. **Classify** by severity (CRITICAL/HIGH/MEDIUM/LOW) -5. **Suggest** fix versions or alternatives +1. **Detect** lockfiles (and whether each is tracked: `git ls-files `). +2. **Check tools** with `command -v`; record absent ones. +3. **Run** the read-only audit command per ecosystem, JSON output where available. +4. **Supply chain** checks: [Supply Chain Checks](references/supply-chain.md). +5. **CI** checks for `.github/workflows/*.yml`: [GitHub Actions Checks](references/ci-github-actions.md). +6. **Classify** each advisory (CRITICAL / HIGH / MEDIUM / LOW, CWE, confidence 1-10). +7. **Verify** each candidate finding in a second read-only pass that tries to refute it: + is the affected version the one actually resolved in the lockfile, is the vulnerable + code reachable (govulncheck does this for Go; elsewhere grep imports/calls), is it a dev-only + dependency. Confidence below 8 goes to "needs manual review", not to findings. +8. **Write** the report with [Report Template](references/templates/audit-report.md) to + `docs/security/YYYY-MM-DD-.md` inside the audited repository. + +## Severity + +Use the advisory's own severity when it states a CVSS score, and record the CVSS version and +source (GitHub, NVD, CNA). Tool labels map as: `critical` → CRITICAL, `high` → HIGH, +`moderate`/`medium` → MEDIUM, `low`/`info` → LOW. These are inputs: the reported severity +follows the plugin's single scale in `rules/security-rules.md`, after reachability. For CVSS details and reachability rules see +the cve-research skill. -## Auto-Fix Support +## Fix options (listed, never run) -When `--fix` flag is used: -- `npm audit fix` / `bun audit fix` for safe updates -- `cargo audit fix` for Rust (experimental; requires `cargo install cargo-audit --features=fix`) -- Manual guidance for other ecosystems +| Ecosystem | Option for the owner | What it changes | +|-----------|---------------------|-----------------| +| bun | `bun audit fix` (`--dry-run` to preview, `--latest` to cross majors) | `bun.lock`, `node_modules`, exact pins in `package.json` | +| npm | `npm audit fix` (`--dry-run`, `--package-lock-only`; `--force` allows SemVer-major) | `package-lock.json`, `node_modules` | +| pnpm | `pnpm audit --fix` (overrides) or `--fix=update` | `pnpm-workspace.yaml` or lockfile | +| Cargo | `cargo audit fix` (`--dry-run`); needs `cargo install cargo-audit --features=fix` | `Cargo.toml` | +| pip | `pip-audit --fix` (`--dry-run` to preview) | installed environment | +| Composer, Go, SwiftPM, Bundler | manual version bump in the manifest, then the package manager's update | manifest + lockfile | ## References -- [Audit Commands](references/audit-commands.md) +- [Audit Commands: JS/TS and PHP](references/audit-commands.md) +- [Audit Commands: Rust, Go, Swift, Python, Ruby, OSV-Scanner](references/audit-commands-systems.md) +- [Supply Chain Checks](references/supply-chain.md) +- [GitHub Actions Checks](references/ci-github-actions.md) - [Report Template](references/templates/audit-report.md) diff --git a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/audit-commands-systems.md b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/audit-commands-systems.md new file mode 100644 index 0000000..49d8d84 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/audit-commands-systems.md @@ -0,0 +1,102 @@ +--- +name: audit-commands-systems +description: Read-only dependency audit commands for Cargo, Go modules, SwiftPM, Python, Bundler and OSV-Scanner, each verified on the tool's official documentation +when-to-use: When auditing a Rust, Go, Swift, Python or Ruby project, or cross-checking any lockfile with OSV-Scanner +keywords: cargo-audit, govulncheck, swiftpm, osv, pip-audit, safety, bundler-audit, osv-scanner +priority: high +related: audit-commands.md, supply-chain.md, templates/audit-report.md +--- + +# Audit Commands: Rust, Go, Swift, Python, Ruby, OSV-Scanner + +Presence check first (`command -v `); absent → `not run: absent`. Read-only +unless marked **FIX (option only)**. + +## Rust — cargo-audit (`Cargo.lock`) + +Source: https://github.com/rustsec/rustsec/tree/main/cargo-audit + +```bash +command -v cargo-audit && rustc --version # cargo audit needs Rust 1.74 or later +# Run from a directory OUTSIDE the audited project, against its lockfile: +cargo audit --file /path/to/project/Cargo.lock --json +``` + +- If `Cargo.lock` is missing, `cargo audit` runs `cargo update --workspace` to create one, and + Cargo reads config from the current directory and can execute project code. Hence `--file` + from outside the project. No `Cargo.lock` → report it (supply-chain finding), do not generate one. +- `cargo audit bin ` audits compiled binaries (fully accurate only if built with + `cargo auditable`). +- **FIX (option only):** `cargo audit fix` edits `Cargo.toml`; `cargo audit fix --dry-run` + previews. Requires `cargo install cargo-audit --features=fix` (experimental). + +## Go — govulncheck (`go.mod`) + +Sources: https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck, https://go.dev/doc/security/vuln/ + +```bash +command -v govulncheck +govulncheck ./... # from the module root; source analysis with call stacks +govulncheck -format json ./... # streaming JSON (exit code 0 regardless of findings) +govulncheck -mode binary ./path/to/bin # compiled binary; no call stacks +``` + +- govulncheck reports vulnerabilities whose vulnerable functions are actually called; use its + call stacks as reachability evidence. Imported-but-not-called advisories go to manual review. +- Limits: calls through `reflect` and `unsafe` may be missed; binary mode can over-report. +- No auto-fix; remediation is a module bump (`go get @`), owner's option. + +## Swift — SwiftPM (`Package.resolved`) and CocoaPods + +There is no SwiftPM audit command. OSV-Scanner's supported lockfiles do not include +`Package.resolved` (https://google.github.io/osv-scanner/supported-languages-and-lockfiles/). +Manual procedure, read-only: + +1. Read each pinned package's repository URL and resolved version from `Package.resolved`. +2. Query OSV with ecosystem `SwiftURL` (name = the Git URL, version = the tag) through + `POST https://api.osv.dev/v1/querybatch` (see cve-research `references/cve-apis.md`). +3. Cross-check GitHub Advisory: `GET https://api.github.com/advisories?ecosystem=swift`. +4. CocoaPods (`Podfile.lock`): no audit command verified; same manual lookup per pod. + +Report the method used; anything not resolvable goes to "needs manual review". + +## Python — pip-audit / Safety + +Sources: https://github.com/pypa/pip-audit, https://docs.safetycli.com/safety-docs/safety-cli/scanning-for-vulnerable-and-malicious-packages/available-commands-and-inputs + +```bash +command -v pip-audit +pip-audit -r requirements.txt -f json +pip-audit --locked . -f json # pyproject.toml / pylock.*.toml lock files +pip-audit -f json # current environment +command -v safety # optional; requires a Safety account (auth or API key) +safety scan --target /path/to/project --output json +``` + +- **FIX (option only):** `pip-audit --fix` (preview with `--fix --dry-run`); + `safety scan --apply-fixes` rewrites requirements files. + +## Ruby — bundler-audit (`Gemfile.lock`) + +Source: https://github.com/rubysec/bundler-audit + +```bash +command -v bundle-audit +bundle-audit check --update --format json # refresh ruby-advisory-db, then check +``` + +- Also flags insecure gem sources (`http://`, `git://`). + +## Any lockfile — OSV-Scanner (optional cross-check) + +Source: https://google.github.io/osv-scanner/usage/ + +```bash +command -v osv-scanner +osv-scanner scan source -r --format json /path/to/project +``` + +- Covers `bun.lock`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `composer.lock`, + `Cargo.lock`, `go.mod`, `Gemfile.lock`, Python lockfiles and more (see supported list above). +- **Never run `osv-scanner fix` in an audit**: the docs warn it can make the package manager + execute scripts or follow registries declared by an untrusted project. diff --git a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/audit-commands.md b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/audit-commands.md index b33baf0..f7b6fc2 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/audit-commands.md +++ b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/audit-commands.md @@ -1,106 +1,110 @@ --- name: audit-commands -description: Dependency audit CLI commands for npm, composer, pip, cargo, go, swift, ruby -when-to-use: When running dependency vulnerability checks on a project -keywords: npm-audit, composer-audit, pip-audit, cargo-audit, govulncheck +description: Read-only dependency audit commands for bun, npm, pnpm, Yarn 2+ and Composer, each verified on the tool's official documentation +when-to-use: When auditing a JS/TS (Next.js, React, TanStack Start, Astro, TypeScript) or PHP/Laravel project +keywords: bun-audit, npm-audit, pnpm-audit, yarn-npm-audit, composer-audit, audit-signatures priority: high -related: templates/audit-report.md +related: audit-commands-systems.md, supply-chain.md, templates/audit-report.md --- -# Audit Commands by Ecosystem +# Audit Commands: JS/TS and PHP -## Node.js +Every block starts with the presence check. Absent tool → `not run: absent` in the +report. Commands below are read-only unless marked **FIX (option only)**. -```bash -# npm -npm audit --json -npm audit fix # Auto-fix safe updates -npm audit fix --force # Force major updates (risky) +## bun (`bun.lock`) -# yarn classic (v1) -yarn audit --json -yarn audit --groups dependencies +Source: https://bun.com/docs/pm/cli/audit -# yarn berry (v2+) — `yarn audit` no longer exists -yarn npm audit --all --recursive --json +```bash +command -v bun +bun audit --json # raw registry JSON; reads bun.lock, no node_modules needed +bun audit --audit-level=high # exit code only counts high+ (low|moderate|high|critical) +bun audit --prod # only dependencies/optionalDependencies/peerDependencies +``` -# pnpm -pnpm audit --json +- `bun audit` never modifies `package.json`, `bun.lock` or `node_modules`. +- `--json` output is unfiltered; `--audit-level` and `--ignore` only change the exit code. +- Packages from a scoped registry without an advisory endpoint are listed as skipped: report them. +- **FIX (option only):** `bun audit fix` upgrades within ranges and installs (changes `bun.lock`, + `node_modules`, and rewrites exact pins in `package.json`); `bun audit fix --dry-run` previews; + `bun audit fix --latest` also crosses majors. -# bun (reads bun.lock) -bun audit --json -bun audit fix # Upgrade within ranges -``` +## npm (`package-lock.json`) -## PHP +Source: https://docs.npmjs.com/cli/v11/commands/npm-audit/ ```bash -# Composer -composer audit --format=json -composer audit --locked # Check lock file only +command -v npm +npm audit --json +npm audit --audit-level=high # failure threshold only, does not filter output +npm audit --omit=dev # skip devDependencies +npm audit signatures # registry signatures + provenance attestations (needs installed packages) ``` -## Python +- npm requires a lockfile to audit; without one, results vary per run (`--no-package-lock`). +- `npm audit signatures` verifies packages already downloaded; recent npm CLI versions are + recommended for attestation checks (check `npm --version`). +- **FIX (option only):** `npm audit fix` (runs a full install), `npm audit fix --dry-run --json` + to preview, `--package-lock-only` to touch only the lockfile, `--force` allows SemVer-major. -```bash -# pip-audit (recommended) -pip-audit --format=json -pip-audit -r requirements.txt - -# safety 3.x (`safety check` is deprecated; requires auth) -safety scan -safety scan --target /path/to/project -``` +## pnpm (`pnpm-lock.yaml`) -## Rust +Source: https://pnpm.io/cli/audit ```bash -# cargo-audit -cargo audit --json -cargo audit --file path/to/Cargo.lock # Untrusted project: never let cargo run in it -cargo audit fix # Experimental: install with `cargo install cargo-audit --features=fix` -cargo audit --deny warnings +command -v pnpm +pnpm audit --json +pnpm audit --audit-level high +pnpm audit --prod +pnpm audit signatures # ECDSA registry signatures against lockfile integrity ``` -## Go +- Never pass `--ignore` or `--ignore-unfixable` during an audit: they write GHSA IDs into + `pnpm-workspace.yaml`. +- **FIX (option only):** `pnpm audit --fix` adds overrides to `pnpm-workspace.yaml`; + `--fix=update` updates the lockfile instead. -```bash -# govulncheck (official) -govulncheck -json ./... -govulncheck -mode=binary ./cmd/app -``` +## Yarn 2+ (`yarn.lock` with `.yarnrc.yml`) -## Swift / CocoaPods +Source: https://yarnpkg.com/cli/npm/audit ```bash -# CocoaPods has no audit command (not in `pod` CLI) -pod outdated -# Check Podfile.lock pods against OSV.dev / GitHub Advisory - -# Swift Package Manager (manual) -# Check Package.resolved against OSV.dev +command -v yarn +yarn npm audit --all --recursive --json # all workspaces, transitive deps, NDJSON +yarn npm audit --environment production # exclude devDependencies ``` -## Multi-ecosystem (OSV-Scanner) +- The default audits only direct dependencies of the active workspace: always pass + `--all --recursive`. +- `yarn npm audit` documents no fix mode; remediation is a manual version bump (owner's option). + +## Yarn 1 classic (`yarn.lock`, no `.yarnrc.yml`) + +Source: https://classic.yarnpkg.com/en/docs/cli/audit ```bash -# Scans bun.lock, package-lock.json, pnpm-lock.yaml, yarn.lock, composer.lock, -# poetry.lock, uv.lock, Cargo.lock, go.mod, Gemfile.lock, ... -osv-scanner scan source -r . +command -v yarn && yarn --version # 1.x = classic +yarn audit --json # JSON lines, needs network +yarn audit --groups dependencies # production dependencies only ``` -## Ruby +- Exit code is a bit mask of severities (1 INFO, 2 LOW, 4 MODERATE, 8 HIGH, 16 CRITICAL); + `--level` filters the table only, not the exit code. + +## Composer (`composer.lock`) + +Source: https://getcomposer.org/doc/03-cli.md (sections `audit` and Global Options) ```bash -# bundler-audit -bundle audit check --format=json -bundle audit update # Update advisory DB +command -v composer +composer audit --locked --format=json --no-plugins --no-scripts +composer audit --locked --no-dev --format=json ``` -## Common Flags - -| Flag | Purpose | -|------|---------| -| `--json` | Machine-readable output | -| `--fix` | Auto-apply safe fixes | -| `--production` | Skip devDependencies | +- `--locked` audits the lockfile regardless of `vendor/`; `--no-plugins` / `--no-scripts` + keep project code from running. +- `composer audit` also reports abandoned packages and packages flagged as malware; exit code + `1` when any dependency policy matches. +- `composer audit` documents no fix mode; remediation is a manual constraint bump in + `composer.json` then `composer update ` (owner's option). diff --git a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/ci-github-actions.md b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/ci-github-actions.md new file mode 100644 index 0000000..3a3de58 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/ci-github-actions.md @@ -0,0 +1,82 @@ +--- +name: ci-github-actions +description: Read-only GitHub Actions workflow checks — action pinning or workflow lockfile, least-privilege permissions, pull_request_target with untrusted checkout, expression injection in run steps, optional zizmor and actionlint +when-to-use: When the audited repository contains .github/workflows/*.yml or action.yml files +keywords: github-actions, sha-pinning, actions-lock, permissions, pull_request_target, script-injection, zizmor, actionlint +priority: high +related: supply-chain.md, templates/audit-report.md +--- + +# GitHub Actions Checks + +Reference: GitHub "Secure use reference" +(https://docs.github.com/en/actions/reference/security/secure-use). Standard for findings: +OWASP Top 10:2025 A03 Software Supply Chain Failures. All checks are read-only. + +## 1. Third-party actions: lockfile or full commit SHA + +GitHub documents a workflow dependency lockfile as the better option than SHA pinning: +`.github/workflows/actions.lock`, +generated by the `gh actions-lock` GitHub CLI extension; it pins every action, including +transitive ones, and supersedes SHA pinning for onboarded workflows +(https://docs.github.com/en/actions/concepts/security/workflow-dependency-lockfiles). +It does not pin reusable workflow calls (`jobs..uses`): those still need a full SHA. + +Without a lockfile, every `uses: owner/repo@ref` must use a full-length commit SHA: + +```bash +ls .github/workflows/actions.lock 2>/dev/null +rg -n "uses:\s*[^.\s][^@\s]*@" .github/workflows .github/actions 2>/dev/null \ + | rg -v "@[0-9a-f]{40}(\s|$|#)" +``` + +Each hit (tag or branch ref, no lockfile) → finding. Why tags are not enough: on 2026-03-19 an +attacker force-pushed 76 of 77 version tags of `aquasecurity/trivy-action` to credential-stealing +code; workflows pinned to a SHA predating the action's own pinning of `setup-trivy` were still +exposed through that unpinned transitive action (GHSA-69fq-xp46-6x23 / CVE-2026-33634, +https://github.com/advisories/GHSA-69fq-xp46-6x23). + +## 2. Least-privilege `permissions:` + +- Every workflow should declare `permissions:` at top level (GitHub recommends read-only + `contents` by default) and raise scopes per job only where needed. +- No `permissions:` key → the job gets the repository default token scope, which the audit + cannot see from files alone → "needs manual review" unless the repo setting is confirmed. +- `permissions: write-all` or broad `write` on a job that runs untrusted input → finding. + +## 3. `pull_request_target` / `workflow_run` with untrusted code + +These triggers run in a privileged context (secrets, write token, shared cache). Finding when +such a workflow checks out pull-request code, e.g. `actions/checkout` with +`ref: ${{ github.event.pull_request.head.sha }}` or `head.ref`, then builds, installs or runs it. + +```bash +grep -rlnE "pull_request_target|workflow_run" .github/workflows +``` + +Open each hit and trace the checkout `ref:` and the steps that follow. + +## 4. Expressions interpolated into `run:` + +`${{ github.event.* }}` (titles, bodies, branch names, commit messages) expanded inside a +`run:` script is a shell injection. The fix GitHub documents: pass the value through `env:` +and use the shell variable (`"$TITLE"`), or pass it to an action input. + +```bash +grep -rnE '\$\{\{\s*github\.event\.' .github/workflows .github/actions +``` + +Keep only hits located inside a `run:` block (or a script input of an action); those are findings. + +## 5. Optional scanners (presence check, never installed) + +```bash +command -v zizmor && zizmor --offline --format=json . # https://docs.zizmor.sh/usage/ +command -v actionlint && actionlint -format '{{json .}}' # https://github.com/rhysd/actionlint/blob/main/docs/usage.md +``` + +- zizmor exit codes 11-14 mean findings (highest severity informational → high); 0 = none. + `--offline` skips audits needing the GitHub API; with a token it runs online audits. +- **FIX (option only):** `zizmor --fix` (safe fixes) / `--fix=all` rewrite workflow files in place. +- actionlint is a correctness linter that also flags untrusted inputs in scripts; treat its + output as evidence for checks 1-4, not as findings on its own. diff --git a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/supply-chain.md b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/supply-chain.md new file mode 100644 index 0000000..f826a5c --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/supply-chain.md @@ -0,0 +1,85 @@ +--- +name: supply-chain +description: Read-only software supply chain checks (OWASP Top 10:2025 A03) — lockfiles, install scripts, registry signatures and provenance, typosquatting, optional SBOM, SLSA reference +when-to-use: During every dependency audit, after the native audit commands +keywords: supply-chain, owasp-a03, lockfile, postinstall, provenance, typosquatting, sbom, slsa +priority: high +related: audit-commands.md, audit-commands-systems.md, ci-github-actions.md +--- + +# Supply Chain Checks + +Standard reference for findings in this file: **OWASP Top 10:2025 A03 Software Supply Chain +Failures** (https://top10.owasp.org/2025/A03_2025-Software_Supply_Chain_Failures/). Its +mapped CWEs include CWE-1104 (unmaintained third-party components) and CWE-1395 (dependency +on vulnerable third-party component). Build-integrity reference to cite: **SLSA v1.2** +(https://slsa.dev/spec/v1.2/), build track (provenance) and source track. + +All checks are read-only. Nothing is installed, nothing is executed from the project. + +## 1. Lockfile present and committed + +```bash +git ls-files bun.lock package-lock.json pnpm-lock.yaml yarn.lock composer.lock \ + Cargo.lock go.sum Package.resolved Gemfile.lock +``` + +- A manifest without its lockfile (or a lockfile listed in `.gitignore`) → finding: installs + are not reproducible (npm states `package-lock.json` is intended to be committed, + https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/). +- Library crates and packages may deliberately omit a lockfile: confidence below 8 → manual review. + +## 2. Install-time scripts + +- npm: packages with `"hasInstallScript": true` in `package-lock.json` run a preinstall, + install or postinstall script (field documented on the page above). List them. +- bun: lifecycle scripts run only for packages in `trustedDependencies` (or Bun's default + list when the field is omitted) — https://bun.com/docs/pm/lifecycle. Review the list in + `package.json`. +- Composer: `scripts` in `composer.json` run on Composer events; audit with `--no-scripts`. +- Grep the repo's own scripts and manifests for remote execution patterns: + +```bash +grep -rnE "curl[^|]*\|\s*(ba|z)?sh|wget[^|]*\|\s*(ba|z)?sh" \ + --include=package.json --include=composer.json --include=*.sh --include=Makefile \ + --include=Dockerfile --include=*.yml --include=*.yaml . +``` + +A `curl … | sh` without a pinned checksum or signature check → finding. + +## 3. Registry signatures and provenance + +- npm: `npm audit signatures` verifies registry signatures and provenance attestations of + installed packages (needs an existing `node_modules`; never install to get one). +- pnpm: `pnpm audit signatures` verifies against lockfile integrity. +- Lockfile `resolved` URLs pointing to a registry other than the expected one, `http://` + sources, or git dependencies without a commit SHA → finding. + +## 4. Typosquatting and newly added packages + +Scope: packages added on the audited branch (`git diff ...HEAD -- `). +For each new name: + +- compare against well-known names (one-character edits, swapped `-`/`_`, scope confusion + such as `@types-foo` vs `@types/foo`); +- check registry metadata: `npm view time repository.url maintainers` (npm, + https://docs.npmjs.com/cli/v11/commands/npm-view/); a first publish date days old, no + repository, or a single new maintainer raises suspicion; +- query OSV / GitHub Advisory for malware records (`type=malware` on + `https://api.github.com/advisories`; Composer flags malware in `composer audit`). + +Suspicion without evidence → manual review, never a finding. + +## 5. SBOM (option, not part of the default run) + +Only when the owner asks, with the tool already present: + +```bash +command -v syft && syft /path/to/project -o cyclonedx-json # https://github.com/anchore/syft +command -v npm && npm sbom # SPDX or CycloneDX, see npm sbom --help +``` + +OSV-Scanner can also emit SPDX / CycloneDX with `--all-packages` +(https://google.github.io/osv-scanner/usage/); read the exact `--format` value from +`osv-scanner --help` before using it. Write SBOM output next to the report, never over a +project file. diff --git a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/templates/audit-report.md b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/templates/audit-report.md index c5c0526..3071303 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/templates/audit-report.md +++ b/.cursor-plugin/plugins/fuse-security/skills/dependency-audit/references/templates/audit-report.md @@ -1,50 +1,66 @@ --- name: audit-report -description: Complete template for dependency audit reports with vulnerability details -keywords: report, dependency, vulnerability, advisory, template +description: Report template for a dependency and supply-chain audit, following the shared finding contract (confidence, CWE, standard reference, refutation pass) +keywords: report, dependency, vulnerability, advisory, supply-chain, template --- -# Dependency Audit Report +# Dependency Audit Report Template -## Header +Write to `docs/security/YYYY-MM-DD-.md` inside the audited repository +(`` e.g. `dependencies`). The audit never applies fixes: remediation commands appear +only under "Fix options". -``` -# Dependency Audit Report -**Project**: {project_name} -**Ecosystem**: {ecosystem} -**Date**: {date} -**Total Dependencies**: {dep_count} -``` +```markdown +# Dependency Audit — {project_name} + +**Date**: {YYYY-MM-DD} **Scope**: {lockfiles and workflow files audited} +**Commit**: {git rev-parse --short HEAD} + +## Tools + +| Tool | Version | Status | +|------|---------|--------| +| bun audit | {bun --version} | run | +| govulncheck | — | not run: govulncheck absent | ## Summary -``` -## Vulnerability Summary -| Severity | Count | -|----------|-------| -| CRITICAL | {critical} | -| HIGH | {high} | -| MEDIUM | {medium} | -| LOW | {low} | -``` +| Severity | Findings | Needs manual review | +|----------|----------|---------------------| +| CRITICAL | {n} | {n} | +| HIGH | {n} | {n} | +| MEDIUM | {n} | {n} | +| LOW | {n} | {n} | -## Vulnerability Detail +## Findings (confidence ≥ 8, survived the refutation pass) -``` -### {package_name}@{current_version} -- **Severity**: {severity} -- **Advisory**: {advisory_url} -- **Description**: {description} -- **Patched Version**: {fix_version} -- **Action**: `npm install {package_name}@{fix_version}` -``` +### {id} — {title} +- **Severity**: {CRITICAL|HIGH|MEDIUM|LOW} — CVSS {version} {score} `{vector}` (source: {GitHub|NVD|CNA}) +- **Confidence**: {8-10}/10 +- **CWE**: {CWE-xxx} +- **Standard**: OWASP Top 10:2025 A03 Software Supply Chain Failures +- **Location**: {package}@{installed_version} via {lockfile} (or {file}:{line} for CI/supply-chain checks) +- **Evidence**: {advisory id + affected range; resolved version from lockfile; reachability evidence} +- **Exploit scenario**: {how an attacker reaches the vulnerable code in this project} +- **Recommendation**: {fixed version or alternative} +- **Refutation pass**: {what was checked to try to disprove it, and why it holds} -## Recommendations +## Needs manual review (confidence < 8) +| Package / file | Advisory or check | Why not confirmed | +|----------------|-------------------|-------------------| + +## Fix options (for the owner — not run by the audit) + +| Command | Changes | +|---------|---------| +| `bun audit fix --dry-run` then `bun audit fix` | bun.lock, node_modules, exact pins in package.json | ``` -## Actions Required -1. Update CRITICAL packages immediately -2. Review HIGH severity for breaking changes -3. Schedule MEDIUM updates for next sprint -4. Document LOW severity in backlog -``` + +## Field rules + +- `id`: stable within the report (`DEP-001`, `SC-001`, `CI-001`) plus the advisory id + (GHSA / CVE / RUSTSEC / GO-…) when one exists. +- Severity from the advisory's CVSS when present; state the CVSS version and who scored it. +- A dev-only dependency that never ships, or a vulnerable function never called, lowers + confidence: report it under manual review unless exploitation in the build path is shown. diff --git a/.cursor-plugin/plugins/fuse-security/skills/security-headers/SKILL.md b/.cursor-plugin/plugins/fuse-security/skills/security-headers/SKILL.md index f84e098..b5b9dd4 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/security-headers/SKILL.md +++ b/.cursor-plugin/plugins/fuse-security/skills/security-headers/SKILL.md @@ -1,58 +1,64 @@ --- name: security-headers -description: "Use when verifying or configuring HTTP security headers (CSP, HSTS, CORS, X-Frame-Options) for a web application (Next.js, Laravel, Express, Django)." -argument-hint: "[framework]" +description: "Use when auditing HTTP security headers (CSP with nonce/hash and strict-dynamic, HSTS, frame-ancestors, Referrer-Policy, Permissions-Policy, COOP/COEP/CORP), cookie attributes or CORS — in code (Next.js, Laravel, Astro, TanStack Start, Express, Django) or live on a URL the owner names." +argument-hint: "[framework] [--live ]" user-invocable: true --- -This skill audits and configures HTTP security headers for a web application: -Content-Security-Policy and Strict-Transport-Security (HIGH severity if missing), -X-Content-Type-Options and X-Frame-Options (MEDIUM), and Referrer-Policy, -Permissions-Policy, X-XSS-Protection (LOW). - -It detects the framework (Next.js next.config.js headers/middleware.ts, Laravel -SecurityHeaders middleware, Express helmet, Django SECURE_* settings), checks the current -configuration against best practice, generates a framework-specific fix, and validates the -headers are properly set. +This skill audits HTTP security headers, cookie attributes and CORS configuration and +reports findings with framework-specific recommendations — it never modifies the audited +project. It covers Content-Security-Policy (strict nonce/hash policies, `strict-dynamic`, +`report-to`), Strict-Transport-Security, X-Content-Type-Options, frame control +(`frame-ancestors` over the obsolete X-Frame-Options), Referrer-Policy, Permissions-Policy, +COOP/COEP/CORP, cookie prefixes and flags, CORS origin handling, and the deprecated +X-XSS-Protection. Values come from OWASP ASVS 5.0.0 V3, the OWASP HTTP Headers and CSP +cheat sheets, MDN and hstspreload.org. + +It can also verify the headers and cookies a running URL actually serves (curl fast path, +then one fuse-browser session when rendering is needed), only on URLs the owner named. # Security Headers Skill -## Overview +## Severity input -Audit and configure HTTP security headers for web applications. +The severity scale for findings is the one in `rules/security-rules.md`; this section is an +input to it. A missing hardening header with no shown attack path is **not a finding** — it +goes to the report's "Hardening notes" section, without severity. It becomes a finding only +with a concrete attack path (XSS sink + no effective CSP, frameable +state-changing page, credentialed CORS reflection on private data, session cookie without +`Secure` on an HTTP-reachable site). Absence of `X-XSS-Protection` or `X-Frame-Options` +(when `frame-ancestors` is set) is never a finding. -## Required Headers +## Workflow -| Header | Purpose | Severity if Missing | -|--------|---------|-------------------| -| Content-Security-Policy | Prevent XSS/injection | HIGH | -| Strict-Transport-Security | Force HTTPS | HIGH | -| X-Content-Type-Options | Prevent MIME sniffing | MEDIUM | -| X-Frame-Options | Prevent clickjacking | MEDIUM | -| Referrer-Policy | Control referrer info | LOW | -| Permissions-Policy | Control browser features | LOW | -| X-XSS-Protection | Legacy XSS filter | LOW | +1. **Detect** the framework and where headers are set: -## Workflow + | Framework | Where to look | + |-----------|---------------| + | Next.js | `next.config.*` `headers()`, `proxy.ts` (formerly `middleware.ts`) | + | Laravel | Custom middleware appended in `bootstrap/app.php`; web server config | + | Astro | `astro.config.*` `security.csp`, adapter `staticHeaders`, `src/middleware.*`, host config | + | TanStack Start | `src/start.ts` request middleware, `setResponseHeader(s)` calls | + | Express | `helmet` usage, `res.setHeader` | + | Django | `SECURE_*`, `X_FRAME_OPTIONS`, CSP middleware settings | + | Any | Reverse proxy / CDN config (nginx `add_header … always`, Vercel/Netlify headers files) | -1. **Detect** framework (Next.js, Laravel, Express, etc.) -2. **Check** current header configuration -3. **Compare** against security best practices -4. **Generate** framework-specific configuration -5. **Validate** headers are properly set +2. **Compare** each header, cookie and CORS rule with [Headers Reference](references/headers-reference.md). +3. **Live check** (only if the owner gave a URL) with [Live Verification](references/live-verification.md) — config in code can be overridden by the proxy/CDN; the served response wins. +4. **Refute** each candidate in a second read-only pass (header set at another layer? route excluded on purpose? API-only JSON where CSP is irrelevant?). +5. **Report** to `docs/security/YYYY-MM-DD-.md` in the audited repository, with recommended snippets from [Config Templates](references/templates/headers-config.md). -## Detection Points +## Finding format (shared contract) -| Framework | Config Location | -|-----------|----------------| -| Next.js | `next.config.js` headers, `middleware.ts` | -| Laravel | `SecurityHeaders` middleware | -| Express | `helmet` middleware | -| Django | `SECURE_*` settings | +id (`HDR-NNN`), title, severity (CRITICAL / HIGH / MEDIUM / LOW), confidence 1-10 (only ≥ 8 +reported; lower → "needs manual review"), CWE, standard (OWASP Top 10:2025 A02 Security +Misconfiguration or A01 for CORS data exposure; OWASP ASVS 5.0.0 `v5.0.0-3.x.y`), file:line +or URL, evidence (header line, secrets redacted), exploit scenario, recommendation. ## References -- [Headers Reference](references/headers-reference.md) -- [Config Templates](references/templates/headers-config.md) +- [Headers Reference](references/headers-reference.md) — values, sources, severity rules, cookies, CORS +- [Config Templates](references/templates/headers-config.md) — Next.js, Laravel, Astro, TanStack Start (verified); Express, Django (not re-verified) +- [Live Verification](references/live-verification.md) — curl + fuse-browser procedure for an owner-named URL diff --git a/.cursor-plugin/plugins/fuse-security/skills/security-headers/references/headers-reference.md b/.cursor-plugin/plugins/fuse-security/skills/security-headers/references/headers-reference.md index 55454f6..35a3f2e 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/security-headers/references/headers-reference.md +++ b/.cursor-plugin/plugins/fuse-security/skills/security-headers/references/headers-reference.md @@ -1,56 +1,105 @@ --- name: headers-reference -description: HTTP security headers reference (CSP, HSTS, CORS, X-Frame-Options, Permissions-Policy) -when-to-use: When auditing or configuring HTTP security headers -keywords: csp, hsts, cors, x-frame-options, referrer-policy, headers +description: HTTP security headers, cookie attributes and CORS reference with recommended values and their primary sources (OWASP ASVS 5.0.0 V3, OWASP HTTP Headers and CSP cheat sheets, MDN, hstspreload.org) +when-to-use: When auditing or recommending HTTP response headers, cookie attributes or CORS configuration +keywords: csp, nonce, strict-dynamic, report-to, hsts, cors, frame-ancestors, x-frame-options, referrer-policy, permissions-policy, coop, coep, corp, cookies priority: high -related: templates/headers-config.md +related: templates/headers-config.md, live-verification.md --- # Security Headers Reference -## Content-Security-Policy (CSP) +Read on 2026-11-10 from: +- **ASVS** — OWASP ASVS 5.0.0 V3 Web Frontend Security, https://github.com/OWASP/ASVS/blob/v5.0.0/5.0/en/0x12-V3-Web-Frontend-Security.md +- **OHH** — OWASP HTTP Security Response Headers Cheat Sheet, https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html +- **OCSP** — OWASP Content Security Policy Cheat Sheet, https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html +- **MDN-XXSS** — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-XSS-Protection +- **HSTSP** — https://hstspreload.org/ -- **Purpose**: Controls which resources the browser can load -- **Recommended**: `default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'` -- **Risk**: XSS attacks if misconfigured -- **Directives**: default-src, script-src, style-src, img-src, connect-src, font-src, frame-src +## Severity input (final severity scale lives in `rules/security-rules.md`) -## Strict-Transport-Security (HSTS) +A missing or weak hardening header with no shown attack path is **not a finding**: list it +under "Hardening notes" (no severity). It becomes a finding only when a concrete attack path +is shown, e.g. a reflected/stored XSS sink plus no effective +CSP, a state-changing page that is frameable (clickjacking), a reflected `Origin` with +`Access-Control-Allow-Credentials: true` on an endpoint returning private data, or a session +cookie without `Secure` on a site reachable over HTTP. -- **Purpose**: Forces HTTPS connections -- **Recommended**: `max-age=63072000; includeSubDomains; preload` -- **Risk**: Man-in-the-middle attacks -- **Note**: Include preload for HSTS preload list +## Content-Security-Policy + +- **Recommended (strict, nonce)** — OCSP "Nonce-based Strict Policy": + `script-src 'nonce-{RANDOM}' 'strict-dynamic'; object-src 'none'; base-uri 'none';` + Hash-based variant: `script-src 'sha256-{HASH}' 'strict-dynamic'; object-src 'none'; base-uri 'none';` +- Nonce: unique random value per response; must be inserted by a templating engine, never by a middleware that rewrites every `` break-out if data is user-supplied | +| `v-html=` (`.vue`) | Vue raw HTML binding | HIGH | sanitized or static content | +| `\{@html ` (`.svelte`) | Svelte raw HTML tag | HIGH | sanitized or static content | +| `bypassSecurityTrust(Html\|Script\|Style\|Url\|ResourceUrl)` | Angular sanitizer bypass | HIGH | constant values | +| `href=\{[^}]*\}` (H) | `javascript:` URL if a user value reaches `href` | MEDIUM | internal route constants | + +React, Vue, Svelte and Astro escape normal interpolation (`{value}`); do not report it as XSS. + +## Code execution (CWE-94 / CWE-95, A05) + +| Regex | Why | Max sev | Common false positive | +|-------|-----|---------|-----------------------| +| `\beval\(` | evaluates a string as code | CRITICAL | method calls such as `redis.eval(` (Lua on the server), dev tooling | +| `new Function\(` | same as eval | CRITICAL | bundler/runtime internals in vendored code | +| `set(Timeout\|Interval)\(\s*["'\x60]` | string argument is evaluated | HIGH | none common | +| `\bvm\.(runIn\w*Context\|Script\|compileFunction)\(` | Node `vm` is not a sandbox for untrusted code | CRITICAL | trusted templates only | + +## Command injection (CWE-78, A05) + +| Regex | Why | Max sev | Common false positive | +|-------|-----|---------|-----------------------| +| `\bexec(Sync)?\(\s*(\x60\|["'][^"']*["']\s*\+\|[^"'\x60)]*\+)` | shell string built from variables | CRITICAL | `regex.exec(` and `db.exec(` (not processes): check the receiver | +| `shell:\s*true` | `spawn`/`execFile` through a shell | HIGH | constant command, no user data | +| `from ['"](node:)?child_process['"]\|require\(['"](node:)?child_process` (H) | locates process APIs to review | review | build scripts that never take request data | + +## SQL / NoSQL injection (CWE-89 / CWE-943, A05) + +| Regex | Why | Max sev | Common false positive | +|-------|-----|---------|-----------------------| +| `\.(query\|execute\|raw)\(\s*\x60[^\x60]*\$\{` | template literal passed to a query function | CRITICAL | tagged templates such as `` sql`...${x}` `` or Prisma `` $queryRaw`...` `` are parameterized | +| `\$(queryRawUnsafe\|executeRawUnsafe)\(` | Prisma raw string APIs | CRITICAL | constant SQL with `$1` placeholders and separate args | +| `\b(sql\.raw\|knex\.raw\|\.whereRaw\|sequelize\.literal\|Sequelize\.literal)\(` | raw fragments in query builders | HIGH | constants; bindings passed separately | +| `\$where\|\$function` | MongoDB server-side JavaScript | HIGH | constant expressions | +| `\.(find\|findOne\|updateOne\|deleteMany)\(\s*req\.(body\|query)` | operator injection (`{"$ne": null}`) | HIGH | body validated by a schema (zod, valibot) before use | + +## SSRF, path traversal, redirects (A01) + +| Regex | Why | Max sev | CWE | Common false positive | +|-------|-----|---------|-----|-----------------------| +| `\b(fetch\|axios(\.\w+)?\|got\|ky\|request)\(\s*(req\.\|request\.\|params\.\|searchParams\|body\.\|input\.)` (H) | user controls the outbound URL | HIGH | CWE-918 | user controls only the path or a query value of a fixed host | +| `(readFile\|createReadStream\|sendFile\|download\|unlink\|writeFile)\w*\(.*(req\.\|params\|query\|body)` (H) | user-controlled file path | HIGH | CWE-22 | value checked with `path.resolve` + prefix check, or mapped through an allowlist | +| `redirect\(\s*(req\.\|searchParams\|params\|body)` (H) | open redirect | MEDIUM | CWE-601 | relative path enforced, allowlist | +| `\b(merge\|extend\|defaultsDeep\|set)\(.*req\.body` (H) | prototype pollution via `__proto__` keys | MEDIUM | CWE-1321 | schema-validated body; `Object.create(null)` targets | + +## Next.js (App Router) + +Source: https://nextjs.org/docs/app/guides/data-security (read 2026-11-10). + +| Regex | Why | Max sev | CWE / OWASP | Common false positive | +|-------|-----|---------|-------------|-----------------------| +| `['"]use server['"]` (H) | every exported Server Action is reachable by a direct POST, and a page-level auth check does not cover the actions defined in it: each action must authenticate and authorize itself | HIGH | CWE-862 / A01 | action delegates to a server-only data access layer that performs the check | +| `export\s+((async\s+)?function\|const)\s+(GET\|POST\|PUT\|PATCH\|DELETE)\b` in `app/**/route.{ts,js}` (H) | Route Handlers are public endpoints | HIGH | CWE-862 / A01 | public read-only data | +| `NEXT_PUBLIC_\w*(SECRET\|PRIVATE\|TOKEN\|PASSWORD\|KEY)` | `NEXT_PUBLIC_` variables are exposed to the client | HIGH | CWE-200 / A01 | keys that are public by design (publishable keys, analytics IDs) | +| `return\s+(await\s+)?(db\|prisma)\.` inside a `'use server'` file (H) | action return values are serialized to the client; raw records can leak fields | MEDIUM | CWE-200 / A01 | DTO with selected fields | + +## TanStack Start + +Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions (read 2026-11-10). + +| Regex | Why | Max sev | CWE / OWASP | Common false positive | +|-------|-----|---------|-------------|-----------------------| +| `createServerFn\(` (H) | server functions are RPC endpoints callable from the browser; each handler (or its middleware) must check authentication, authorization and input | HIGH | CWE-862 / A01 | auth enforced in attached middleware | +| file `src/start.ts` exists and `createCsrfMiddleware` does not appear in it (H) | Start installs its CSRF middleware for server functions automatically only when `src/start.ts` does not exist; a custom `src/start.ts` must add it explicitly | MEDIUM | CWE-352 / A01 | CSRF middleware added elsewhere in the same `createStart` | + +## Cryptography and TLS + +| Regex | Why | Max sev | CWE / OWASP | Common false positive | +|-------|-----|---------|-------------|-----------------------| +| `Math\.random\(` (H) | not a CSPRNG | MEDIUM (HIGH for tokens, IDs used as secrets) | CWE-338 / A04 | UI jitter, sampling, non-security IDs | +| `createHash\(\s*['"](md5\|sha1)['"]` | broken for signatures/passwords | MEDIUM | CWE-327 / CWE-328 / A04 | ETags, cache keys, non-security checksums | +| `createCipheriv\(\s*['"][^'"]*-ecb['"]` | ECB leaks plaintext patterns | HIGH | CWE-327 / A04 | none common | +| `rejectUnauthorized:\s*false\|NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*['"]?0` | TLS certificate validation disabled | HIGH | CWE-295 / A07 | local test servers in test files | + +JWT, sessions, OAuth and password hashing: [auth-audit](../../auth-audit/SKILL.md). Headers, CSP and +CORS configuration: [security-headers](../../security-headers/SKILL.md). Dependencies and lockfiles: +[dependency-audit](../../dependency-audit/SKILL.md). + +## Exceptional conditions (A10) + +| Regex | Why | Max sev | CWE | Common false positive | +|-------|-----|---------|-----|-----------------------| +| `catch\s*(\([^)]*\))?\s*\{\s*\}` | swallowed error | MEDIUM | CWE-390 | best-effort cleanup (log close, temp delete) | +| `catch[^{]*\{[^}]*(return true\|next\(\))` (H) | fail-open in a guard | CRITICAL in authn/authz/payment | CWE-636 | non-security middleware | +| `res\.(send\|json)\(.*\.stack` | stack trace returned to client | MEDIUM | CWE-209 | dev-only handler guarded by environment check | diff --git a/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/secrets-patterns.md b/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/secrets-patterns.md new file mode 100644 index 0000000..ebb63d8 --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/secrets-patterns.md @@ -0,0 +1,127 @@ +--- +name: secrets-patterns +description: Single source of secret-detection patterns (private keys, cloud keys, tokens, committed env files) plus optional git-history scanning +when-to-use: When looking for hardcoded credentials, private keys, or committed .env files in any repository +keywords: secrets, credentials, private key, api key, token, env, gitleaks, betterleaks, trufflehog +priority: high +related: triage.md, sast-tools.md, owasp-top10.md +--- + +# Secret Patterns (single source) + +Other skills and rules link here; do not copy this list elsewhere. + +## Reporting rule (ZERO TOLERANCE) + +A report NEVER prints a secret value, not even partially masked. Report only `file:line`, the secret +type (rule name below) and whether the file is tracked by git. Do not paste matching lines into the +report, logs or messages to other agents. + +## Scope: what regex sees + +These patterns run on the working tree only. A secret removed from the current files can still live +in git history, in other branches and in tags. For history, use the optional tools at the end +(presence-checked, never installed by the agent). + +Run with `rg -n --hidden --no-ignore-vcs -e ''` (Rust regex syntax; no lookaround is +used). `-e` is required: the private-key regex starts with `-` and would otherwise be parsed as a +flag. `--no-ignore-vcs` matters: a `.env` committed before it was added to `.gitignore` is still +tracked, and plain `rg` would skip it. Alternative limited to tracked files: +`git ls-files -z | xargs -0 rg -n -e ''` (the patterns use Rust regex syntax, which +`git grep -E` rejects). In the tables, `\|` is only the Markdown escape for `|`: type a plain +`|` in the regex. Search all files, not only source globs: secrets sit in `.env*`, `*.json`, +`*.yml`, `*.toml`, `*.xml`, `*.plist`, `*.properties`, `*.ini`, `*.tf`, `*.tfvars`, notebooks and +shell scripts. Exclude `node_modules`, `vendor`, `.git` with `--glob '!node_modules'` etc. + +## Private keys and certificates + +| Rule | Regex | Severity | CWE | +|------|-------|----------|-----| +| private-key (PKCS#1 RSA, EC, DSA, OPENSSH, PKCS#8 generic, ENCRYPTED, PGP) | `-----BEGIN [A-Z ]*PRIVATE KEY( BLOCK)?-----` | CRITICAL | CWE-321 | +| key file present | file names `id_rsa`, `id_ed25519`, `id_ecdsa`, `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.jks`, `*.keystore` | HIGH (verify content) | CWE-321 | + +False positive: test fixtures in `test/`, `testdata/`, `fixtures/` with obviously fake keys, and +public keys / certificates (`BEGIN PUBLIC KEY`, `BEGIN CERTIFICATE` do not match the regex). +`ENCRYPTED PRIVATE KEY` is still reported: the passphrase is often next to it. + +## Cloud provider keys + +| Rule | Regex | Severity | CWE | +|------|-------|----------|-----| +| aws-access-key-id | `\b(AKIA\|ASIA)[0-9A-Z]{16}\b` | CRITICAL if a secret key is near | CWE-798 | +| aws-secret-access-key (heuristic) | `(?i)aws_?secret_?access_?key\s*[:=]\s*['"]?[A-Za-z0-9/+=]{40}` | CRITICAL | CWE-798 | +| gcp-service-account | `"type"\s*:\s*"service_account"` in a file that also contains `"private_key"` | CRITICAL | CWE-798 | +| google-api-key | `\bAIza[0-9A-Za-z_-]{35}\b` | HIGH (scope-dependent) | CWE-798 | +| azure-storage-connection-string | `DefaultEndpointsProtocol=https?;AccountName=[^;]+;AccountKey=` | CRITICAL | CWE-798 | + +False positive: AWS documentation example keys (they contain `EXAMPLE`); Google browser API keys +restricted by referrer are designed to ship to clients (still check restrictions). + +## Common token formats + +| Rule | Regex | Severity | CWE | +|------|-------|----------|-----| +| github-token | `\b(ghp\|gho\|ghu\|ghs\|ghr)_[A-Za-z0-9]{36}\b` | CRITICAL | CWE-798 | +| github-fine-grained-pat | `\bgithub_pat_[A-Za-z0-9_]{20,}` | CRITICAL | CWE-798 | +| gitlab-pat | `\bglpat-[A-Za-z0-9_-]{20,}` | CRITICAL | CWE-798 | +| slack-token | `\bxox[abposr]-[A-Za-z0-9-]{10,}` | HIGH | CWE-798 | +| slack-webhook | `https://hooks\.slack\.com/services/[A-Za-z0-9/]+` | MEDIUM | CWE-798 | +| stripe-secret | `\b(sk\|rk)_live_[A-Za-z0-9]{16,}` | CRITICAL | CWE-798 | +| stripe-test-secret | `\b(sk\|rk)_test_[A-Za-z0-9]{16,}` | LOW | CWE-798 | +| anthropic-key | `\bsk-ant-[A-Za-z0-9_-]{20,}` | CRITICAL | CWE-798 | +| openai-style-key (heuristic, broad) | `\bsk-(proj-)?[A-Za-z0-9_-]{20,}` | HIGH | CWE-798 | +| npm-token | `\bnpm_[A-Za-z0-9]{36}\b` | CRITICAL | CWE-798 | +| npmrc-auth | `_authToken\s*=\s*[^\s$]` in `.npmrc` | CRITICAL | CWE-798 | +| sendgrid-key | `\bSG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}` | HIGH | CWE-798 | +| jwt (heuristic) | `\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}` | MEDIUM | CWE-798 | +| db-url-with-password | `(?i)\b(postgres(ql)?\|mysql\|mariadb\|mongodb(\+srv)?\|redis\|amqps?)://[^:/\s"']+:[^@/\s"']+@` | HIGH | CWE-798 | + +Token prefixes are vendor formats; when a regex above is marked heuristic, the format is not +fixed enough to be conclusive. `pk_live_` / `pk_test_` (Stripe publishable) are public by design: do +not report. JWTs in tests and docs are usually sample tokens: check the payload (`exp`, `iss`) +without printing it. + +## Generic assignments (heuristic) + +| Rule | Regex | Severity | CWE | +|------|-------|----------|-----| +| generic-secret-assignment | `(?i)\b[\w-]*(password\|passwd\|pwd\|secret\|api_?key\|access_?token\|auth_?token\|private_?key)[\w-]*\s*[:=]\s*['"][^'"\s]{8,}['"]` | HIGH until triaged | CWE-798 / CWE-259 | +| swift-literal-key | `let\s+\w*(apiKey\|secret\|token)\w*\s*=\s*"[^"]{8,}"` | HIGH until triaged | CWE-798 | + +False positive: placeholders (`changeme`, `your-api-key`, `xxx`, `<...>`, `${VAR}`, `process.env.X`, +`env('X')`, `os.environ[...]`), i18n strings such as `password: "Password"`, form field names, +and test fixtures. Values read from environment variables are not hardcoded secrets. + +## Committed environment and credential files + +```bash +git ls-files | rg '(^|/)\.env(\.[^/]*)?$' | rg -v '\.(example|sample|template|dist)$' +git ls-files | rg '(^|/)(\.npmrc|\.pypirc|\.netrc|\.git-credentials|credentials\.json|service-account.*\.json)$' +``` + +A tracked `.env` with real values is HIGH (CRITICAL with production credentials), CWE-538, OWASP +A02:2025. An untracked `.env` listed in `.gitignore` is normal: do not report it. + +## Mapping + +Hardcoded credentials (CWE-798, CWE-259) → A07:2025 Authentication Failures; hardcoded crypto keys +(CWE-321) → A04:2025 Cryptographic Failures; committed config files → A02:2025 (see +[owasp-top10.md](owasp-top10.md)). Severity is confirmed in the [triage pass](triage.md): a live +production credential is CRITICAL, a revoked or test-only credential is LOW. + +## Optional: git history and broader secret scanners + +Presence-check only: `command -v betterleaks gitleaks trufflehog`. Never install. If none is +present, say "git history not scanned" in the report's scanner coverage section. + +| Tool | Status read today (2026-11-10) | Command (as read on the official page) | +|------|-------------------------------|----------------------------------------| +| Betterleaks | Maintained by the Gitleaks authors; `main` is v2 development and the README states that until the first stable v2 release package managers may still provide v1 (https://github.com/betterleaks/betterleaks) | check `betterleaks --version` first. v2: `betterleaks git ` (history), `betterleaks fs ` (filesystem). v1 (https://github.com/betterleaks/betterleaks/tree/v1.x): `betterleaks git `, `betterleaks dir ` | +| Gitleaks | README warning: feature complete, future releases are security patches only, author points to Betterleaks (https://github.com/gitleaks/gitleaks) | not written: usage section not verified today | +| TruffleHog | AGPL-3.0 licence (badge and LICENSE on https://github.com/trufflesecurity/trufflehog) | `trufflehog git file:// --no-verification` | + +Validation modes contact the credential provider with the found secret (Betterleaks v2 `-v` / +`-a`, Betterleaks v1 `--validation`, TruffleHog verification, e.g. `--results=verified`: owner consent only). On Betterleaks v2, `-v` means validate, not verbose (v2 migration guide: +https://github.com/betterleaks/betterleaks/blob/main/docs/v2_migration.md). Do not enable them without the owner's explicit consent; Betterleaks +detection without validation is its default (same README). Tool output contains raw secrets: read it, +then report only `file:line`, commit and rule type. diff --git a/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/templates/scan-report.md b/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/templates/scan-report.md index b2d28c7..ef05910 100644 --- a/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/templates/scan-report.md +++ b/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/templates/scan-report.md @@ -1,63 +1,112 @@ --- name: scan-report -description: Complete template for structured security scan reports with OWASP mapping -keywords: report, template, findings, severity, owasp +description: Template for security scan reports - shared finding fields, scanner coverage, needs manual review, re-test after fix +keywords: report, template, findings, severity, confidence, owasp, cwe, coverage, retest --- # Security Scan Report Template +Write the report in the audited repository at `docs/security/YYYY-MM-DD-.md` +(`` = `full`, a path such as `api`, or `diff-`). Never print a secret value: secrets +are reported as `file:line` + type only ([secrets-patterns.md](../secrets-patterns.md)). The agent +reports; it does not fix. + ## Header ``` # Security Scan Report **Project**: {project_name} -**Date**: {date} -**Language**: {language} -**Framework**: {framework} +**Date**: {YYYY-MM-DD} +**Scope**: full repository | {path} | diff vs {base} (merge base {sha}), {n} files changed +**Languages / frameworks detected**: {list, from project markers and file extensions} +**Commit**: {git rev-parse HEAD} ``` -## Executive Summary +## Summary ``` -## Summary -| Severity | Count | -|----------|-------| -| CRITICAL | {critical_count} | -| HIGH | {high_count} | -| MEDIUM | {medium_count} | -| LOW | {low_count} | -| **Total** | **{total_count}** | +| Severity | Findings (confidence ≥ 8) | +|----------|---------------------------| +| CRITICAL | {n} | +| HIGH | {n} | +| MEDIUM | {n} | +| LOW | {n} | +Needs manual review: {n} Dropped after refutation: {n} ``` -## Findings Section +## Scanner coverage + +State what was actually scanned; never imply coverage that did not happen. ``` +### Automated pass +- Harness scanner: ran | not available — command: `npx -y @fusengine/harness scan ` +- Coverage printed by the scanner: {languages and file counts as printed} | "no coverage summary printed" +- Present in the repo but NOT reported as scanned: {languages / extensions} → covered manually with {reference files} + +### Optional tools (presence-checked, never installed) +| Tool | Present | Ran | Note | +|------|---------|-----|------| +| semgrep / opengrep | yes/no | yes/no | rules used; git-tracked files only | +| codeql | yes/no | yes/no | licence condition checked | +| betterleaks / gitleaks / trufflehog | yes/no | yes/no | git history scanned: yes/no | + +### Manual pass +- Pattern references applied: {files} +- Excluded paths: {node_modules, vendor, build output, ...} +``` + ## Findings -### [CRITICAL] {finding_title} -- **File**: `{file_path}:{line_number}` -- **Category**: {owasp_category} -- **Pattern**: `{matched_pattern}` -- **Description**: {description} -- **Remediation**: {fix_instructions} +One block per finding, confidence ≥ 8 only, ordered by severity. + +``` +### {id} [{SEVERITY}] {title} +- **Confidence**: {8-10}/10 +- **CWE**: CWE-{n} +- **Standard**: A{nn}:2025 {category} [+ API{n}:2023 for API code] +- **Location**: `{file}:{line}` +- **Evidence**: {source → sink trace in words; quote code only if it contains no secret} +- **Exploit scenario**: {concrete attacker steps and what they obtain} +- **Recommendation**: {smallest change that removes the vulnerability} +- **Re-test after fix**: {exact command or check, e.g. `rg -n '' {file}` returns nothing, plus the behaviour to verify} +``` + +`id` format: `SEC-001`, `SEC-002`, … stable within the report. + +## Needs manual review + +Candidates scored 5-7: what is plausible, and the one fact that would confirm or refute it. + +``` +| Candidate | Location | Confidence | What to check | +|-----------|----------|------------|---------------| +| {title} | `{file}:{line}` | {5-7} | {config value, caller, deployment detail} | ``` -## Dependency Audit Section +## Hardening notes + +Missing hardening with no shown attack path (for example an absent security header): no +severity, not counted as a finding. + +``` +- {title} — `{file}:{line}` or {URL}: {suggested change} +``` + +## Re-test after fix + +The checklist the caller runs once fixes are applied (one row per finding): ``` -## Dependency Audit -| Package | Current | Patched | Severity | Advisory | -|---------|---------|---------|----------|----------| -| {pkg} | {ver} | {fix} | {sev} | {url} | +| ID | Check to re-run | Expected result | +|----|-----------------|-----------------| +| SEC-001 | `{command}` | {no match / request rejected / test passes} | ``` -## Recommendations +## Out of scope / delegated ``` -## Recommendations -1. Fix all CRITICAL findings immediately -2. Update vulnerable dependencies -3. Add security headers (CSP, HSTS) -4. Review authentication patterns -5. Enable audit logging +- Dependencies and CVEs: dependency-audit / cve-research report {path or "not run"} +- Auth flows: auth-audit {path or "not run"} +- Security headers: security-headers {path or "not run"} ``` diff --git a/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/triage.md b/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/triage.md new file mode 100644 index 0000000..fa8c22a --- /dev/null +++ b/.cursor-plugin/plugins/fuse-security/skills/security-scan/references/triage.md @@ -0,0 +1,106 @@ +--- +name: triage +description: Verification of candidate findings - refutation pass, confidence 1-10, threshold 8, severity by impact and exploitability, classes not reported without an attack path +when-to-use: After the scanner and manual patterns produced candidates, before anything is written in the report +keywords: triage, false positive, refutation, confidence, severity, exploit scenario, verification +priority: high +related: scan-patterns.md, secrets-patterns.md, sast-tools.md, templates/scan-report.md +--- + +# Triage: from match to finding + +A scanner hit, a grep match or an engine result is a **candidate**. It becomes a **finding** only +after this pass. The agent reports findings; it does not fix them. + +## Why a separate verification pass + +- Anthropic's public security-review command + (https://raw.githubusercontent.com/anthropics/claude-code-security-review/main/.claude/commands/security-review.md, + read 2026-11-10) splits the work in two: one pass identifies candidates, then each candidate is + re-examined in its own sub-task against false-positive rules, and anything scored below 8 out of + 10 is dropped. It asks for a concrete exploit scenario per finding and favours missing a + theoretical issue over flooding the report. This skill follows the same structure, in its own + words and with its own exclusion list below. +- Snyk VulnBench JS 1.0 (https://snyk.io/blog/snyk-vulnbench-js-1-0-llm-security-review-repeatability/, + 2026-06-29; a vendor study by a SAST vendor, measured against its own tool's reference set) ran + repeated identical LLM reviews: findings that matched the reference set were mostly stable, while + model-only extra findings were not (80 of 161 unique unmatched findings appeared in only one of + five identical runs). Its conclusion is to combine deterministic analysis with model review. + Hence: deterministic tools where available ([sast-tools.md](sast-tools.md)) plus this + read-only refutation pass on every candidate. + +## Refutation pass (read-only, per candidate) + +Try to prove the candidate wrong. Record each answer; one decisive "no" ends it. + +1. **Source**: where does the value come from? Trace it backwards to an HTTP request, CLI input + from an untrusted user, file upload, message queue, third-party API or database field written + by users. Environment variables and deployment config are trusted. +2. **Sink**: does the traced value reach the dangerous call unchanged, or through code that + validates, encodes, parameterizes or allowlists it? +3. **Framework protection**: auto-escaping templates (JSX, Blade `{{ }}`, Jinja autoescape, Razor), + parameterized tagged templates and ORMs, built-in CSRF middleware, server-only modules. A + framework protection that is bypassed explicitly (raw HTML, raw SQL, disabled middleware) does + not count. +4. **Reachability**: is the code reachable in production (route registered, export used, feature + flag on)? Who can reach it (anonymous, any user, admin only)? +5. **File nature**: test, fixture, example, documentation, generated or vendored code? Then the + candidate is not reported, unless it ships in the production artifact. +6. **Exploit scenario**: write the concrete steps an attacker takes and what they obtain. No + scenario, no finding. + +## Confidence (1-10) + +| Score | Meaning | Destination | +|-------|---------|-------------| +| 9-10 | source, sink and reachability confirmed in the code; scenario concrete | Findings | +| 8 | clear vulnerable pattern with a known exploitation method; one minor assumption | Findings | +| 5-7 | plausible, depends on something the code does not show (config, caller, deployment) | Needs manual review (state what to check) | +| 1-4 | refuted or speculative | dropped; count only, in the coverage section | + +Threshold: **only confidence ≥ 8 is reported as a finding.** + +## Severity (impact × exploitability) + +Same scale as the single definition in the plugin's `rules/security-rules.md`; the rows below +restate it with triage examples. + +| Severity | Definition | +|----------|------------| +| CRITICAL | exploitable by an unauthenticated or any low-privilege user, leading to code execution, authentication bypass, bulk data access/modification, or a live production credential | +| HIGH | exploitable with realistic preconditions, leading to another user's data or account, stored XSS, SSRF into internal services, privilege escalation | +| MEDIUM | needs specific conditions (user interaction, non-default config, insider position) or has limited impact | +| LOW | real weakness with a shown attack path but minor impact; a defense-in-depth gap with no attack path is a hardening note (no severity), not a finding | + +The severity verified here overrides the raw label printed by the automated scanner and the "max +severity" column of the pattern references. Example: a `child_process` import or a `mysql_query(` +call may be labelled CRITICAL or HIGH by a tool; its verified severity depends on whether user input +reaches it and who can reach the code. + +## Classes not reported without a concrete attack path + +These are reported only when the refutation pass yields a specific, reachable exploit; otherwise +they go to "needs manual review" or are dropped: + +- denial of service, resource exhaustion, regex DoS. Exceptions that ARE findings (the reachable + endpoint is the attack path; severity by the scale above): a missing rate limit on an + authentication, password-reset, OTP or other abuse-prone endpoint, and a GraphQL endpoint + without depth/cost limits that is reachable without authentication (see + [graphql-security.md](graphql-security.md)). The same gaps without a shown path go to + "Hardening notes", never silently dropped; +- missing hardening that is not itself a vulnerability (absent header, absent audit log); +- theoretical race conditions and timing attacks; +- open redirect, prototype pollution, tabnabbing, XS-Leaks; +- SSRF where the user controls only the path or a query value, not the host or protocol; +- missing checks in client-side code (the server is the trust boundary); +- XSS in React/Vue/Svelte/Astro components that do not use a raw-HTML API; +- logging of non-sensitive data (secrets, passwords and personal data in logs are reportable); +- command injection in shell scripts or CI workflows that no untrusted input reaches; +- outdated dependencies (handled by [dependency-audit](../../dependency-audit/SKILL.md)); +- anything in tests, fixtures, examples or documentation files. + +## Second read-only pass + +Before writing the report, re-read every finding at its `file:line` with fresh context (a separate +sub-task when available) and re-score it. A finding whose score drops below 8 moves to "needs manual +review". Neither pass edits files. From 079ef0330cf764d9b036317a91d8bbcb0fa9780b Mon Sep 17 00:00:00 2001 From: Bruno Azoulay Date: Tue, 10 Nov 2026 04:49:23 +0100 Subject: [PATCH 2/2] chore: bump marketplace and CHANGELOG to 0.1.11 --- .cursor-plugin/marketplace.json | 4 ++-- .../plugins/fuse-security/.cursor-plugin/plugin.json | 2 +- CHANGELOG.md | 11 +++++++++++ README.md | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json index 0d33468..729d420 100644 --- a/.cursor-plugin/marketplace.json +++ b/.cursor-plugin/marketplace.json @@ -6,7 +6,7 @@ }, "metadata": { "description": "Professional Cursor plugins with APEX workflow, SOLID principles, and expert development agents for Next.js, Laravel, Swift, Tailwind CSS, and more", - "version": "0.1.10" + "version": "0.1.11" }, "plugins": [ { @@ -411,7 +411,7 @@ "name": "fuse-security", "source": ".cursor-plugin/plugins/fuse-security", "description": "Security vulnerability detection and remediation: OWASP Top 10, SAST scanning, CVE research, dependency audit, secrets detection", - "version": "1.0.19", + "version": "1.0.20", "author": { "name": "Fusengine", "email": "hello@fusengine.ch" diff --git a/.cursor-plugin/plugins/fuse-security/.cursor-plugin/plugin.json b/.cursor-plugin/plugins/fuse-security/.cursor-plugin/plugin.json index faf18a8..0c0af03 100644 --- a/.cursor-plugin/plugins/fuse-security/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugins/fuse-security/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "fuse-security", - "version": "1.0.19", + "version": "1.0.20", "description": "Security vulnerability detection and remediation: OWASP Top 10, SAST scanning, CVE research, dependency audit, secrets detection", "author": { "name": "Fusengine", diff --git a/CHANGELOG.md b/CHANGELOG.md index 3443e76..24aadba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [0.1.11] - 10-11-2026 + +- feat(security): port the claude-plugins security plugin refresh (v1.39.47) — + new `agentic-security` skill; `auth-audit`, `cve-research`, `dependency-audit`, + `security-headers`, `security-scan` skills (new references), `security-expert` + agent, `scan` command and rules refreshed; Cursor adaptations (scan via + `npx -y @fusengine/harness scan `, agent model grok-4.6, Agent → Task) +- chore(plugins): PATCH bump, mirrored in `.cursor-plugin/marketplace.json` — + fuse-security 1.0.20 +- chore(marketplace): suite `metadata.version` 0.1.10 → 0.1.11, README version badge updated + ## [0.1.10] - 09-11-2026 - docs(ai-pilot): port the claude-plugins lead-corrections rules (49e2ea35) — diff --git a/README.md b/README.md index fe61520..6c3b6e9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Fusengine Cursor Plugins -![version](https://img.shields.io/badge/version-0.1.10-blue?style=flat-square) +![version](https://img.shields.io/badge/version-0.1.11-blue?style=flat-square) ![plugins](https://img.shields.io/badge/plugins-25-brightgreen?style=flat-square) ![runtime](https://img.shields.io/badge/runtime-Cursor%20CLI-black?style=flat-square) ![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)