@rafter-security/cli 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +20 -1
  2. package/dist/commands/agent/audit-skill.js +2 -1
  3. package/dist/commands/agent/audit.js +27 -0
  4. package/dist/commands/agent/components.js +800 -0
  5. package/dist/commands/agent/disable.js +47 -0
  6. package/dist/commands/agent/enable.js +50 -0
  7. package/dist/commands/agent/index.js +6 -0
  8. package/dist/commands/agent/init.js +162 -164
  9. package/dist/commands/agent/list.js +72 -0
  10. package/dist/commands/brief.js +20 -0
  11. package/dist/commands/docs/index.js +18 -0
  12. package/dist/commands/docs/list.js +37 -0
  13. package/dist/commands/docs/show.js +64 -0
  14. package/dist/commands/mcp/server.js +84 -0
  15. package/dist/commands/skill/index.js +14 -0
  16. package/dist/commands/skill/install.js +89 -0
  17. package/dist/commands/skill/list.js +79 -0
  18. package/dist/commands/skill/registry.js +273 -0
  19. package/dist/commands/skill/remote.js +333 -0
  20. package/dist/commands/skill/review.js +975 -0
  21. package/dist/commands/skill/uninstall.js +65 -0
  22. package/dist/core/audit-logger.js +262 -21
  23. package/dist/core/config-manager.js +3 -0
  24. package/dist/core/docs-loader.js +148 -0
  25. package/dist/core/policy-loader.js +72 -1
  26. package/dist/index.js +6 -0
  27. package/package.json +1 -1
  28. package/resources/skills/rafter/SKILL.md +76 -96
  29. package/resources/skills/rafter/docs/backend.md +106 -0
  30. package/resources/skills/rafter/docs/cli-reference.md +199 -0
  31. package/resources/skills/rafter/docs/finding-triage.md +79 -0
  32. package/resources/skills/rafter/docs/guardrails.md +91 -0
  33. package/resources/skills/rafter/docs/shift-left.md +64 -0
  34. package/resources/skills/rafter-code-review/SKILL.md +91 -0
  35. package/resources/skills/rafter-code-review/docs/api.md +90 -0
  36. package/resources/skills/rafter-code-review/docs/asvs.md +120 -0
  37. package/resources/skills/rafter-code-review/docs/cwe-top25.md +78 -0
  38. package/resources/skills/rafter-code-review/docs/investigation-playbook.md +101 -0
  39. package/resources/skills/rafter-code-review/docs/llm.md +87 -0
  40. package/resources/skills/rafter-code-review/docs/web-app.md +84 -0
  41. package/resources/skills/rafter-secure-design/SKILL.md +103 -0
  42. package/resources/skills/rafter-secure-design/docs/api-design.md +97 -0
  43. package/resources/skills/rafter-secure-design/docs/auth.md +67 -0
  44. package/resources/skills/rafter-secure-design/docs/data-storage.md +90 -0
  45. package/resources/skills/rafter-secure-design/docs/dependencies.md +101 -0
  46. package/resources/skills/rafter-secure-design/docs/deployment.md +104 -0
  47. package/resources/skills/rafter-secure-design/docs/ingestion.md +98 -0
  48. package/resources/skills/rafter-secure-design/docs/standards-pointers.md +102 -0
  49. package/resources/skills/rafter-secure-design/docs/threat-modeling.md +128 -0
  50. package/resources/skills/rafter-skill-review/SKILL.md +106 -0
  51. package/resources/skills/rafter-skill-review/docs/authorship-provenance.md +82 -0
  52. package/resources/skills/rafter-skill-review/docs/changelog-review.md +99 -0
  53. package/resources/skills/rafter-skill-review/docs/data-practices.md +88 -0
  54. package/resources/skills/rafter-skill-review/docs/malware-indicators.md +79 -0
  55. package/resources/skills/rafter-skill-review/docs/prompt-injection.md +85 -0
  56. package/resources/skills/rafter-skill-review/docs/telemetry.md +78 -0
@@ -0,0 +1,91 @@
1
+ # Rafter Guardrails — PreToolUse Hooks & Command Risk
2
+
3
+ How Rafter intercepts agent tool calls before they execute, how it decides what to block, and how to override safely.
4
+
5
+ ## The Shape
6
+
7
+ Rafter exposes two hook handlers over stdio:
8
+
9
+ - `rafter hook pretool` — read a JSON event on stdin (from Claude Code, etc.), emit an approve/block decision on stdout.
10
+ - `rafter hook posttool` — read a JSON event after a tool ran; log to audit trail, optionally rescan written files for secrets.
11
+
12
+ For platforms without hooks, the same classifier is reachable as:
13
+ - `rafter agent exec --dry-run -- <command>` (returns risk, exits 0/1)
14
+ - `rafter mcp serve` → MCP tool `evaluate_command`
15
+
16
+ ## Risk Tiers
17
+
18
+ Every command (Bash-like tool call) gets classified into one of four tiers by `src/core/risk-rules.ts`:
19
+
20
+ | Tier | What it means | Default hook behavior |
21
+ |---|---|---|
22
+ | `low` | Read-only, safe prefix (`ls`, `cat`, `grep`, `git status` …), no chaining | **approve** silently |
23
+ | `medium` | State-changing but recoverable (package installs, git commits on current branch) | **approve with note** in audit log |
24
+ | `high` | Destructive or privileged (force push, `sudo`, broad file deletion, curl | sh) | **prompt** the agent / user for approval |
25
+ | `critical` | Likely irreversible damage (`rm -rf /`, DB drop, wiping .git, repo-wide chmod) | **block** hard |
26
+
27
+ Tiers are derived from regex patterns in `risk-rules.ts` (`CRITICAL_PATTERNS`, `HIGH_PATTERNS`, `MEDIUM_PATTERNS`) plus a `SAFE_PREFIX` allowlist. Presence of chain operators (`&&`, `||`, `;`, `|`) disqualifies the safe-prefix shortcut.
28
+
29
+ ## Policy Overrides
30
+
31
+ `.rafter.yml` (project) and `~/.rafter/config.yml` (global) can override defaults:
32
+
33
+ ```yaml
34
+ risk:
35
+ blocked_patterns:
36
+ - "terraform destroy"
37
+ require_approval:
38
+ - "^npm publish"
39
+ allow:
40
+ - "^pnpm run test" # force low regardless of content
41
+ ```
42
+
43
+ Merge order (most specific wins): project `.rafter.yml` > global config > built-in defaults. Dump the effective merged policy with `rafter policy export`.
44
+
45
+ ## How to Interpret a Block
46
+
47
+ When a hook blocks a command, the JSON response includes:
48
+
49
+ - `decision`: `"block" | "approve" | "ask"`
50
+ - `riskLevel`: `"critical" | "high" | "medium" | "low"`
51
+ - `reason`: the matched pattern or policy rule
52
+ - `ruleId`: stable ID you can reference in overrides / suppressions
53
+
54
+ **Before overriding, ask: is there a safer form of this command?** Example:
55
+ - `rm -rf $DIR` with unvalidated `$DIR` → use explicit path or `--one-file-system`.
56
+ - `curl <url> | sh` → download, inspect, then run.
57
+ - `git push --force` → `git push --force-with-lease`.
58
+
59
+ ## How to Request an Override
60
+
61
+ If the block is a false positive **for this specific context**, the right path is:
62
+
63
+ 1. Add an allow pattern scoped to the project in `.rafter.yml`:
64
+ ```yaml
65
+ risk:
66
+ allow:
67
+ - "^terraform destroy -target=module\\.sandbox"
68
+ ```
69
+ 2. Or run once with an explicit ack flag: `rafter agent exec --force -- <command>` (logged to audit trail; still shows up in `rafter agent audit` history).
70
+ 3. Never disable the hook globally to get past one command — that silently drops protection for every future call.
71
+
72
+ ## Audit Trail
73
+
74
+ Every hook decision (approve / ask / block) is appended to the JSONL audit log:
75
+
76
+ - Location: `rafter agent status` prints the path.
77
+ - Read: `rafter agent audit --log` (or MCP `read_audit_log`).
78
+ - Use it for postmortems: *why did this command run?*, *what did the agent try before the block?*
79
+
80
+ ## Platform Notes
81
+
82
+ - **Claude Code**: `rafter agent init --with-claude-code` wires `pretool` + `posttool` into `~/.claude/settings.json`. Hook timeout is 5s; long scans defer to the async posttool path.
83
+ - **MCP clients (Gemini, Cursor, …)**: no native hook; use the `evaluate_command` MCP tool from your agent's system prompt ("before Bash, call rafter.evaluate_command").
84
+ - **CI**: hooks don't fire in CI. Use `rafter scan` + `rafter policy validate` in the pipeline instead.
85
+
86
+ ## Common Pitfalls
87
+
88
+ - A `low` classification is not a safety guarantee — it means "no known-bad pattern matched". Still review unusual commands.
89
+ - Chaining defeats the safe-prefix allowlist on purpose (`ls && rm -rf /` is not low-risk).
90
+ - `sudo` always escalates to at least `high` regardless of the wrapped command.
91
+ - Secret leaks in arguments (`curl -H "Authorization: Bearer abc..."`) are flagged by posttool scanning, not by the pretool risk classifier.
@@ -0,0 +1,64 @@
1
+ # Shift-Left — Secure Design & Code Review Skills
2
+
3
+ `rafter` (this skill) handles **detection**: scanners, hooks, risk classifiers. Two sibling skills cover the earlier stages of the lifecycle — use them when prevention or structured review is more valuable than another scan pass.
4
+
5
+ ## Decision Tree
6
+
7
+ | You're trying to … | Reach for |
8
+ |---|---|
9
+ | Write code that **doesn't have the flaw in the first place** (design phase, picking primitives, shaping APIs) | `rafter-secure-design` |
10
+ | **Review existing code** against OWASP Top 10 / MITRE ATT&CK / ASVS with a structured walkthrough | `rafter-code-review` |
11
+ | Find concrete bugs / leaks / CVEs automatically | stay in this skill — see branch (a) in SKILL.md |
12
+
13
+ The three skills compose: design well (secure-design) → write it → review it (code-review) → detect what slipped through (rafter scan + guardrails).
14
+
15
+ ## `rafter-secure-design` (filed as rf-bcr)
16
+
17
+ Use at feature kickoff or during architecture review, *before* code exists. It's a CYOA over design decisions:
18
+
19
+ - Authn / authz primitives: which to pick, which to refuse (e.g. homegrown JWT signing).
20
+ - Input boundaries: where to validate, where to escape, where to parameterize.
21
+ - Secrets handling: storage, rotation, scoping of least-privilege credentials.
22
+ - Data-in-transit / data-at-rest defaults per language/framework.
23
+ - Threat modeling prompts: STRIDE-style walks you can run with an agent.
24
+
25
+ Invoke it by name in platforms that auto-trigger skills, or:
26
+ ```bash
27
+ rafter brief shift-left # this doc
28
+ # and then load the sibling:
29
+ # Read skills/rafter-secure-design/SKILL.md
30
+ ```
31
+
32
+ ## `rafter-code-review` (landed)
33
+
34
+ Use during code review — your own or an AI's. A CYOA router into OWASP / MITRE / ASVS walkthroughs phrased as *questions*, not as monolithic audits. It's the *analysis* counterpart to automated scanning.
35
+
36
+ Pick the category that matches the code in front of you:
37
+
38
+ - **Web app** → `rafter-code-review/docs/web-app.md` (OWASP Top 10 2021).
39
+ - **REST / GraphQL / gRPC API** → `rafter-code-review/docs/api.md` (OWASP API Top 10 2023).
40
+ - **LLM-integrated feature** → `rafter-code-review/docs/llm.md` (OWASP LLM Top 10 2025).
41
+ - **CLI / library / IaC** → `rafter-code-review/docs/cwe-top25.md` (MITRE CWE Top 25, keyed by language).
42
+ - **Need to pick review depth** → `rafter-code-review/docs/asvs.md` (ASVS L1/L2/L3 selection + spot-checks).
43
+ - **Single suspicious finding to chase** → `rafter-code-review/docs/investigation-playbook.md`.
44
+
45
+ Start at `rafter-code-review/SKILL.md` — it's a router; Read only the one sub-doc you need so you don't flood context.
46
+
47
+ Pair with `rafter run --mode plus` when you want both a human-style walkthrough and the backend's deep pass on the same diff.
48
+
49
+ ## When to use which (cheat sheet)
50
+
51
+ - Designing a new service → **secure-design**.
52
+ - Reviewing a teammate's PR by eye → **code-review**.
53
+ - CI gate / pre-push / scheduled scan → **rafter** (this skill), `rafter run` / `rafter scan local`.
54
+ - "I have a finding, now what?" → **rafter**, `docs/finding-triage.md`.
55
+ - "I have a risky command, is it safe?" → **rafter**, `docs/guardrails.md`.
56
+
57
+ Do not duplicate. If a sibling skill already owns the topic, Read it and stop — don't re-derive the checklist here.
58
+
59
+ ## Status
60
+
61
+ - `rafter-code-review` — **landed** (rf-z7j). Ships alongside this skill; invoke directly.
62
+ - `rafter-secure-design` — **landed** (rf-bcr). Ships alongside this skill; invoke directly. Router skill with sub-docs for auth, data storage, API design, ingestion, deployment, dependencies, threat modeling, and standards pointers.
63
+
64
+ Both are installed — prefer invoking them directly for structured output over re-deriving checklists here.
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: rafter-code-review
3
+ description: "Structured security code review — OWASP / MITRE / ASVS walkthroughs as questions, not audits. Router skill: pick what kind of code you're reviewing (web app, REST/GraphQL API, LLM-integrated, CLI/library/IaC) and Read the matching sub-doc. Designed to pair with `rafter scan` / `rafter run` — the scanner finds known-bad patterns, this skill asks the questions that patterns miss. Use during PR review, refactoring risky modules, or pre-release hardening."
4
+ version: 0.7.0
5
+ allowed-tools: [Bash, Read, Glob, Grep]
6
+ ---
7
+
8
+ # Rafter Code Review — Structured Security Walkthroughs
9
+
10
+ A reviewer's skill, not an audit generator. Each sub-doc is a set of **questions** to run against the code — what to grep for, what to trace, what to ask before you sign off. No monolithic reports.
11
+
12
+ > Pair with the `rafter` skill (detection: `rafter scan`, `rafter run`) and `rafter-secure-design` (prevention: design-phase walks). This skill is the middle stage — review before merge.
13
+
14
+ ## How to use this skill
15
+
16
+ 1. Identify the category of code in front of you (below).
17
+ 2. `Read` only the matching sub-doc — do not preload them all.
18
+ 3. Work through its questions against the specific files/diff. Cite file:line evidence as you go.
19
+ 4. When in doubt on a single finding, jump to `docs/investigation-playbook.md` for canonical follow-up questions.
20
+ 5. Finish with `rafter run --mode plus` on the same diff if the stakes warrant a deep automated pass.
21
+
22
+ ---
23
+
24
+ ## Choose Your Adventure
25
+
26
+ ### (1) Web application (server-rendered, session-based, or SPA backend)
27
+
28
+ For: login flows, session/cookie handling, form handlers, template rendering, admin panels, anything browser-facing.
29
+
30
+ - **Read `docs/web-app.md`** — OWASP Top 10 (2021) walk: broken access control, crypto failures, injection, insecure design, misconfig, vulnerable components, authn failures, integrity failures, logging gaps, SSRF.
31
+
32
+ ### (2) REST / GraphQL / gRPC API (machine-to-machine, mobile backend, public API)
33
+
34
+ For: endpoint surface that isn't primarily rendering HTML — tokens instead of sessions, authz-per-endpoint, rate limiting.
35
+
36
+ - **Read `docs/api.md`** — OWASP API Security Top 10 (2023): BOLA, broken authn, BOPLA, unrestricted resource consumption, BFLA, unrestricted access to sensitive business flows, SSRF, misconfig, improper inventory, unsafe consumption of third-party APIs.
37
+
38
+ ### (3) LLM-integrated feature (prompts, agents, tools, RAG, embeddings)
39
+
40
+ For: anything that sends user text to a model, uses tool calls, retrieves untrusted context, or ships model output to a downstream system.
41
+
42
+ - **Read `docs/llm.md`** — OWASP LLM Top 10 (2025): prompt injection, sensitive info disclosure, supply chain, data/model poisoning, improper output handling, excessive agency, system prompt leakage, vector/embedding weaknesses, misinformation, unbounded consumption.
43
+
44
+ ### (4) CLI, library, or infra-as-code
45
+
46
+ For: build tooling, developer CLIs, shared SDK packages, Terraform / CloudFormation / Kubernetes manifests, shell scripts.
47
+
48
+ - **Read `docs/cwe-top25.md`** — MITRE CWE Top 25, keyed by language (Python / JS / Go / Rust / Java) and by IaC primitive. Focus on injection, memory safety, path traversal, race conditions, privilege mismanagement.
49
+
50
+ ### (5) I need to pick the right depth for this review
51
+
52
+ For: "how hard should I look?", scoping a review before starting, compliance-adjacent changes.
53
+
54
+ - **Read `docs/asvs.md`** — OWASP ASVS L1 / L2 / L3. Picks the level based on risk tier of the code, then gives spot-check questions per level.
55
+
56
+ ### (6) I have one specific question to investigate
57
+
58
+ For: single-finding follow-up, tracing a suspicious call, "is this input reachable from outside?".
59
+
60
+ - **Read `docs/investigation-playbook.md`** — canonical questions: reachability, authz coverage, data-flow direction, trust boundary placement.
61
+
62
+ ---
63
+
64
+ ## What this skill will NOT do
65
+
66
+ - It will not generate a monolithic "security audit report". If you need a report, run `rafter run --mode plus` — the backend is better at that.
67
+ - It will not replace automated scanning. Always pair with `rafter scan local .` (secrets) and `rafter run` (SAST/SCA) before review.
68
+ - It will not produce recommendations without evidence. Every question expects a file:line answer before moving on.
69
+
70
+ ---
71
+
72
+ ## Fast path for a typical PR review
73
+
74
+ ```bash
75
+ # 1. Run deterministic checks first — cheap, catches the obvious
76
+ rafter scan local .
77
+ rafter run # remote SAST/SCA, if RAFTER_API_KEY set
78
+
79
+ # 2. Then pick the category and walk the questions
80
+ # Read docs/<category>.md
81
+ ```
82
+
83
+ If the diff spans categories (e.g. a web app that also has an LLM feature), Read both sub-docs and walk them sequentially. Don't try to merge the checklists.
84
+
85
+ ---
86
+
87
+ ## Tie-backs
88
+
89
+ - Finding from the scanner you don't understand? → `rafter` skill, `docs/finding-triage.md`.
90
+ - Designing a new feature instead of reviewing one? → `rafter-secure-design`.
91
+ - Risky command came up mid-review? → `rafter` skill, `docs/guardrails.md`.
@@ -0,0 +1,90 @@
1
+ # API Review — OWASP API Security Top 10 (2023)
2
+
3
+ REST / GraphQL / gRPC review: authz-per-endpoint, per-object and per-field; rate limiting; bulk operations. Walk each category as questions. Cite file:line before moving on.
4
+
5
+ ## API1 — Broken Object Level Authorization (BOLA)
6
+
7
+ The most common API vuln. Per-object authz, not per-endpoint.
8
+
9
+ - For every handler that takes an id (`/orders/:id`, `/users/:user_id/settings`), is there a check that the id belongs to the caller? "Authenticated" is not "authorized".
10
+ - Grep patterns: `findById`, `SELECT ... WHERE id = ?`, `get_object_or_404`. Is the caller's identity in the query, or compared after?
11
+ - GraphQL: authz at the resolver level for *each* field that returns a user-owned object. Schema-level auth is not enough if resolvers fan out.
12
+ - UUIDs do not save you. They only slow discovery; they do not provide authorization.
13
+
14
+ ## API2 — Broken Authentication
15
+
16
+ - Every unauthenticated endpoint — is it supposed to be? List them: grep for `@AnonymousAllowed`, `permission_classes = []`, middleware skips.
17
+ - Token lifetime, refresh, and revocation: where is a token invalidated on logout / password change / user deletion?
18
+ - JWT-specific: is `alg` pinned? Is the key rotated? Is `iss` / `aud` checked? Is clock skew bounded?
19
+ - API keys: how are they generated (entropy), stored (hashed?), scoped (per-tenant? per-capability?), rotated?
20
+ - Credential endpoints (login, reset, MFA enroll) — rate-limited separately from normal endpoints? Return generic errors? Constant-time compare?
21
+
22
+ ## API3 — Broken Object Property Level Authorization (BOPLA)
23
+
24
+ Covers both mass-assignment and excessive data exposure.
25
+
26
+ - Serialization: when returning an object, are sensitive fields (`password_hash`, `mfa_secret`, `internal_notes`, `role`) explicitly excluded? "Return the model" is a red flag; "return a DTO" is the fix.
27
+ - Mass assignment: can the client set fields they shouldn't? `User.objects.update(**request.data)`, `req.body` spread into an ORM constructor, Rails `params.permit!`. Check every update/create path.
28
+ - GraphQL: schema exposes fields; are resolvers authz-checked per field? Can a non-admin introspect admin-only fields?
29
+
30
+ ## API4 — Unrestricted Resource Consumption
31
+
32
+ - Pagination on every list endpoint? Max page size enforced server-side (not just a default)?
33
+ - Rate limits: per-user, per-IP, per-endpoint. Token bucket? What happens at the limit — 429 with `Retry-After`, or silent 500?
34
+ - Request size limits: body size, file upload size, JSON depth, GraphQL query depth / complexity.
35
+ - Expensive operations: image processing, PDF generation, report export — are they queued, timeboxed, cost-accounted?
36
+ - Amplification: does one API call trigger N outbound calls (email, SMS, push)? Can that N be user-controlled?
37
+
38
+ ## API5 — Broken Function Level Authorization (BFLA)
39
+
40
+ Different from BOLA — this is "can a regular user invoke an admin function at all?", not "can user A touch user B's data?".
41
+
42
+ - List admin / privileged endpoints. For each, is there a role check? Is the role from a trusted source (session/token claim) or from the request (`X-Role: admin`)?
43
+ - HTTP verb confusion: does the handler accept PUT/PATCH/DELETE when only GET was authz'd? Are method restrictions on the router or in the handler?
44
+ - Feature flags: does the flag gate *access* or only *visibility*? If the endpoint is reachable when the flag is off, the flag isn't security.
45
+
46
+ ## API6 — Unrestricted Access to Sensitive Business Flows
47
+
48
+ - Identify flows worth abusing: signup, promo code redemption, ticket/inventory purchase, "add friend", "send invite".
49
+ - Per-flow: is there anti-automation (captcha, proof of work, device fingerprint, delay between steps)? Rate limit per account *and* per payment instrument *and* per IP range?
50
+ - Does the flow leak enumeration? Signup "email already registered" is a known tradeoff — is it the right one here?
51
+
52
+ ## API7 — Server-Side Request Forgery
53
+
54
+ (Same question set as web-app A10 — see `web-app.md`.)
55
+
56
+ - Webhook configurators, URL-based imports, OAuth discovery endpoints, image fetchers: any user-supplied URL that the server fetches?
57
+ - DNS rebinding: is the URL resolved once and then reused, or re-resolved on each redirect? Are redirects followed blindly?
58
+ - Cloud metadata (`169.254.169.254`, `metadata.google.internal`) explicitly blocked?
59
+
60
+ ## API8 — Security Misconfiguration
61
+
62
+ - Error responses: do they include stack traces, SQL fragments, internal hostnames? Production should return stable error shapes only.
63
+ - CORS per-endpoint: any endpoint with `Allow-Credentials: true` *and* a reflected / wildcard origin?
64
+ - Default routes from frameworks still mounted (`/actuator/*`, `/debug/*`, `/_next/*` in dev mode)?
65
+ - Are OPTIONS responses correctly restrictive? Do HEAD and OPTIONS follow the same authz as GET?
66
+ - TLS: are older APIs allowed to accept plain HTTP for backwards compat? If yes — is that documented and scoped?
67
+
68
+ ## API9 — Improper Inventory Management
69
+
70
+ A governance issue, but reviewable:
71
+
72
+ - Is there an API version registry? When this PR adds or changes an endpoint, is it documented (OpenAPI / GraphQL schema committed)?
73
+ - Are deprecated endpoints marked and scheduled for removal? Still reachable in production?
74
+ - Non-prod environments (staging, sandbox) — do they share data, credentials, or network paths with prod? Often the weakest link.
75
+
76
+ ## API10 — Unsafe Consumption of Third-Party APIs
77
+
78
+ - Outbound API calls: is the response validated before use (schema, size, type)? "Trust the third party" is the failure mode.
79
+ - Credentials to third parties: scoped to least privilege? Rotated? Not shared across tenants?
80
+ - What happens on timeout / 5xx from the third party? Fallback to cached data? Log and surface?
81
+ - If the third party is compromised, what is the blast radius here? Does our data flow into untrusted callbacks?
82
+
83
+ ---
84
+
85
+ ## Exit criteria
86
+
87
+ - Every endpoint touched by the diff has a documented answer for API1 (per-object authz) and API5 (per-function authz).
88
+ - Every new third-party integration has answers for API10.
89
+ - Every new flow has a rate-limit story (API4) and an abuse story (API6).
90
+ - Scanner cross-check: run `rafter run` and reconcile SAST findings against this walk.
@@ -0,0 +1,120 @@
1
+ # OWASP ASVS — Picking a Level, Spot-Checking It
2
+
3
+ The Application Security Verification Standard (ASVS 4.0 / 5.0) is a catalog of verification requirements. Unlike Top 10 lists, it's exhaustive — which is why you pick a level first and spot-check, not walk every item.
4
+
5
+ ## Step 1 — Pick the right level
6
+
7
+ | Level | Use for | Rough test |
8
+ |---|---|---|
9
+ | **L1** — Opportunistic | Low-value apps, internal tooling, marketing sites. "Protect against casual, opportunistic attackers." | Would losing this data be annoying but not damaging? |
10
+ | **L2** — Standard | Most apps that handle user data, B2B SaaS, line-of-business apps. "Default for apps handling sensitive data." | PII, payment, auth, health-adjacent, B2B tenants? |
11
+ | **L3** — Advanced | Apps where compromise leads to real harm: financial transactions, healthcare records, critical infrastructure, high-trust platforms. | Regulatory scrutiny? Lives/money at risk? |
12
+
13
+ **Rule of thumb**: pick the lowest level that matches the *highest-sensitivity* data flow in the scope. Don't average. A single admin endpoint that touches payment data pulls the whole service to L2 for that endpoint.
14
+
15
+ ---
16
+
17
+ ## Step 2 — Spot-check (not walk-every-item)
18
+
19
+ ASVS has 280+ requirements. You will not walk them all in a PR review. Instead, for the level you picked, ask the three questions below per category.
20
+
21
+ ### V1 — Architecture, Design, Threat Modeling
22
+
23
+ - Is there a threat model for this feature? (L2+: yes; L3: reviewed and signed.)
24
+ - Are all components inventoried (deps, services, data stores)?
25
+ - Does the design document trust boundaries and assumptions?
26
+
27
+ ### V2 — Authentication
28
+
29
+ - Password policy: min length 8 (L1) / 12 (L2) / 12+MFA (L3); hashed with argon2/bcrypt/scrypt; never truncated or case-normalized in storage.
30
+ - MFA: not required at L1; required for admin/sensitive at L2; required for all at L3.
31
+ - Credential recovery: does not bypass MFA; uses time-limited, single-use tokens; does not leak account existence.
32
+
33
+ ### V3 — Session Management
34
+
35
+ - Server-side session store (or stateless token with revocation)?
36
+ - Session rotation on login / privilege change / logout?
37
+ - Cookie flags: `Secure`, `HttpOnly`, `SameSite=Lax` or stricter; `Domain` scoped tightly.
38
+
39
+ ### V4 — Access Control
40
+
41
+ - Deny-by-default on new endpoints?
42
+ - Per-object authz (BOLA) enforced where user ids appear in URLs?
43
+ - Admin functions require re-authentication at L2+; require MFA step-up at L3.
44
+
45
+ ### V5 — Validation, Sanitization, Encoding
46
+
47
+ - Input: validated at the trust boundary (not downstream) against a positive spec (allowlist, schema, regex anchored).
48
+ - Output: context-aware encoding (HTML / URL / JSON / shell / SQL). Templating auto-escapes?
49
+ - Parsers: safe loaders for YAML/XML/JSON; no string-concat into query languages.
50
+
51
+ ### V6 — Stored Cryptography
52
+
53
+ - Algorithms: AES-GCM, ChaCha20-Poly1305, SHA-256+, HMAC-SHA-256+, PBKDF2/argon2 for passwords.
54
+ - Key management: keys not in source, rotated, scoped per-environment, stored in a managed KMS at L2+.
55
+ - Randomness: `secrets` / `crypto.randomBytes` / `crypto/rand` — never `rand()` / `Math.random()`.
56
+
57
+ ### V7 — Error Handling & Logging
58
+
59
+ - No secrets / PII in logs (grep log statements).
60
+ - No stack traces to the user in production.
61
+ - Authn, authz, and sensitive actions logged with who/when/what.
62
+
63
+ ### V8 — Data Protection
64
+
65
+ - PII classified? Access to it logged?
66
+ - Data at rest encrypted (disk, DB, backups, cache)? Keys managed separately?
67
+ - Data in transit: TLS 1.2+ with modern ciphers; HSTS.
68
+
69
+ ### V9 — Communications
70
+
71
+ - TLS everywhere, including internal hops? At L3, mutual TLS between services.
72
+ - Certificate validation not disabled anywhere (grep `InsecureSkipVerify`, `verify=False`, `rejectUnauthorized: false`).
73
+
74
+ ### V10 — Malicious Code
75
+
76
+ - No hardcoded backdoors, debug logins, "magic" accounts.
77
+ - Build pipeline integrity: signed artifacts, locked deps, reproducible where possible.
78
+
79
+ ### V11 — Business Logic
80
+
81
+ - Sequential flows (checkout, signup, reset): can steps be skipped? Replayed? Reordered?
82
+ - Anti-automation on abuse-prone flows (captcha, proof of work, device fingerprint)?
83
+
84
+ ### V12 — Files & Resources
85
+
86
+ - Uploads: type-sniffed (not extension-trusted), size-limited, stored outside web root, name-randomized.
87
+ - Downloads: path-confined; no `../` traversal; MIME set explicitly.
88
+ - Archives: zip-slip / tar-slip prevention when extracting.
89
+
90
+ ### V13 — API & Web Service
91
+
92
+ - OpenAPI / GraphQL schema present and matches implementation?
93
+ - Auth per-endpoint, not per-service?
94
+ - Rate limits per-endpoint tier?
95
+
96
+ ### V14 — Configuration
97
+
98
+ - Production config reviewed (debug off, defaults rotated, unused features off)?
99
+ - Dependencies: SCA in CI, lockfile committed, base images pinned.
100
+ - Secrets: none in source, rotated on exposure, scoped per environment.
101
+
102
+ ---
103
+
104
+ ## Step 3 — What to produce
105
+
106
+ Not an ASVS report. A list of **citations** keyed by (level, category, requirement), plus **gaps**. Example:
107
+
108
+ ```
109
+ L2 / V4.1.3 (deny by default) — OK, `authMiddleware` registered globally in app.ts:41
110
+ L2 / V4.2.1 (per-object authz) — GAP, /orders/:id handler (orders.ts:88) lacks owner check
111
+ L2 / V5.1.1 (schema validation) — OK, zod schemas in routes/*.ts
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Tie-backs
117
+
118
+ - Concrete vulnerabilities (not requirements): go to `web-app.md` / `api.md` / `llm.md`.
119
+ - Specific finding investigation: `investigation-playbook.md`.
120
+ - Automated coverage: `rafter run --mode plus` produces ASVS-tagged findings.
@@ -0,0 +1,78 @@
1
+ # CWE Top 25 — Language-Keyed Checklist
2
+
3
+ MITRE's CWE Top 25 is weakness-level, not risk-level. Use this for CLI tools, libraries, IaC, and anything where OWASP's web/API framing doesn't fit. Pick the language section; pair with language-specific linters.
4
+
5
+ ## How to use
6
+
7
+ - Grep the patterns below against the diff. Each hit is a question, not a verdict.
8
+ - Cross-reference with `rafter run` — the backend catches many of these via SAST; this doc covers the ones that take context to judge.
9
+
10
+ ---
11
+
12
+ ## Cross-language (applies everywhere)
13
+
14
+ - **CWE-79 XSS / CWE-89 SQLi / CWE-78 OS Command Injection** — any user input reaching a query language, shell, or HTML sink. Fix at the sink: parameterize, array-exec, autoescape.
15
+ - **CWE-22 Path Traversal** — any `open(path)`, `fs.readFile(path)`, `os.path.join(base, user_input)`. Canonicalize (`realpath` / `filepath.Abs`) and verify the result stays under an allow-root.
16
+ - **CWE-352 CSRF** — state-changing endpoints: is there a token check? SameSite cookies are necessary but not sufficient for cross-site POSTs in older browsers / API clients.
17
+ - **CWE-287 Improper Authentication / CWE-862 Missing Authorization** — covered in web-app.md / api.md.
18
+ - **CWE-798 Hardcoded Credentials** — `rafter scan local .` catches literal secrets; manually check env-var defaults (`API_KEY = os.environ.get("KEY", "dev-fallback-abc123")` ships the fallback).
19
+ - **CWE-918 SSRF** — any user-supplied URL fetched server-side. See web-app.md A10.
20
+
21
+ ---
22
+
23
+ ## Python
24
+
25
+ - **CWE-502 Insecure Deserialization** — `pickle.load`, `pickle.loads`, `yaml.load` without `SafeLoader`, `shelve`, `marshal`. Any of these on untrusted bytes is RCE.
26
+ - **CWE-78 / Subprocess** — `subprocess.run(..., shell=True)` with user input. Use list form: `subprocess.run(["cmd", arg])`, never `shell=True` with interpolated input.
27
+ - **CWE-94 Code Injection** — `eval`, `exec`, `compile`, `__import__` with user input. Also `pd.eval`, `numexpr.evaluate`.
28
+ - **CWE-611 XXE** — `xml.etree.ElementTree` is safe by default in 3.7+, but `lxml.etree.parse` with `resolve_entities=True` is not. Prefer `defusedxml`.
29
+ - **CWE-327 Weak Crypto** — `hashlib.md5` / `sha1` on passwords; `random` (not `secrets`) for tokens; `Crypto.Cipher.DES`, `AES.MODE_ECB`.
30
+ - **CWE-20 Input Validation** — type coercion pitfalls: `int(x)` raises, `int(x, 16)` accepts leading `0x`, `float("inf")`.
31
+
32
+ ## JavaScript / TypeScript
33
+
34
+ - **CWE-1321 Prototype Pollution** — `_.merge`, `Object.assign` with user-controlled source, recursive deep-merge on user JSON. Node: affects the whole process.
35
+ - **CWE-79 XSS** — `innerHTML`, `outerHTML`, `document.write`, `dangerouslySetInnerHTML`, `v-html`, `$sce.trustAsHtml`. React's default is safe; anything that bypasses it is the finding.
36
+ - **CWE-94 Code Injection** — `eval`, `new Function(str)`, `setTimeout(str, ...)`, `setInterval(str, ...)`, `vm.runInThisContext` with user input.
37
+ - **CWE-22 Path Traversal** — `path.join(base, userInput)` does not protect. Must resolve and verify containment.
38
+ - **CWE-400 Regex DoS (ReDoS)** — catastrophic backtracking patterns: `(a+)+`, `(.*)*`. Especially user-provided regexes.
39
+ - **CWE-346 Origin Validation** — `postMessage` handlers that don't check `event.origin`. `addEventListener("message", ...)` without origin check is the bug.
40
+
41
+ ## Go
42
+
43
+ - **CWE-369 Divide-by-Zero / CWE-190 Integer Overflow** — Go doesn't panic on overflow, it wraps. Slice indexing with computed sizes: `make([]byte, headerLen)` where `headerLen` is attacker-controlled.
44
+ - **CWE-362 Race Conditions** — map writes without mutex; goroutines sharing non-channel state; `context.Value` for mutable data. Run `go test -race`.
45
+ - **CWE-74 Injection / CWE-78** — `exec.Command(name, args...)` is safe; `sh -c <string>` is not. Check `exec.Command("sh", "-c", userInput)`.
46
+ - **CWE-295 Improper Certificate Validation** — `tls.Config{InsecureSkipVerify: true}` outside tests.
47
+ - **CWE-400 Resource Consumption** — `io.ReadAll` on untrusted streams with no `io.LimitReader`. Goroutine leaks: for every `go f()`, how does it exit?
48
+ - **CWE-665 Improper Initialization** — zero-value structs used as "valid" config; `sync.Mutex` copied by value.
49
+
50
+ ## Rust
51
+
52
+ - **CWE-119 Buffer Issues** — `unsafe` blocks. Every `unsafe` needs a comment explaining the invariant; missing comments are findings.
53
+ - **CWE-362 Race Conditions** — despite borrow checker, `Arc<Mutex<T>>` misuse (holding across `.await`), `RefCell` in multi-threaded code (→ `RwLock`).
54
+ - **CWE-674 Uncontrolled Recursion** — `serde` with deeply nested JSON, manual recursive parsers without depth limit.
55
+ - **CWE-400 Resource Consumption** — `.collect::<Vec<_>>()` on untrusted iterator; `Bytes::from` without length cap.
56
+ - **CWE-704 Incorrect Type Conversion** — `as` casts that truncate silently (`u64 as u32`). Prefer `try_into()`.
57
+
58
+ ## Java / Kotlin
59
+
60
+ - **CWE-502 Insecure Deserialization** — `ObjectInputStream.readObject` on untrusted bytes; XMLDecoder; Jackson with default typing (`@JsonTypeInfo(use = Id.CLASS)` + polymorphic).
61
+ - **CWE-611 XXE** — `DocumentBuilderFactory` / `SAXParserFactory` without disabling external entities. Default is unsafe in older Java.
62
+ - **CWE-22 Path Traversal** — `Paths.get(base, userInput)` doesn't check containment; use `toRealPath().startsWith(base)`.
63
+ - **CWE-917 Expression Language Injection** — SpEL, OGNL, MVEL with user input (classic Struts-style RCE).
64
+
65
+ ## IaC (Terraform / CloudFormation / Kubernetes)
66
+
67
+ - **CWE-284 Improper Access Control** — security groups with `0.0.0.0/0` on admin ports (22, 3389, db ports); S3 buckets public; IAM policies with `Resource: "*"` + `Action: "*"`.
68
+ - **CWE-732 Incorrect Permissions** — file modes `0777`, world-writable volumes, ConfigMaps holding secrets.
69
+ - **CWE-319 Cleartext Transmission** — ELB listeners on port 80 without redirect; storage without encryption at rest; TLS versions < 1.2.
70
+ - **CWE-798 Hardcoded Credentials** — secrets in `*.tf`, `*.yaml` environment, `docker-compose.yml`.
71
+ - **CWE-1104 Unmaintained 3rd-Party** — Docker base images pinned to `latest` or unpinned digests; Helm charts from unreviewed repos.
72
+
73
+ ---
74
+
75
+ ## Exit criteria
76
+
77
+ - For each language in the diff, walked the relevant section. For each hit, either a file:line citation showing it's safe, or a finding filed.
78
+ - Run language-specific linters in CI (`bandit`, `semgrep`, `golangci-lint`, `cargo clippy`, `spotbugs`) — this skill complements, doesn't replace them.
@@ -0,0 +1,101 @@
1
+ # Investigation Playbook — Canonical Questions per Category
2
+
3
+ When one finding, suspicious pattern, or vague "this looks wrong" needs a follow-up — use this. Each section is a question you can actually answer with Grep / Read / trace.
4
+
5
+ ## Reachability: "Can untrusted input get here?"
6
+
7
+ Before fixing anything, prove it's reachable.
8
+
9
+ - Where does the input originate? Trace upward from the sink: `app.post(...)` → handler → service → ... → the line in question.
10
+ - Are there layers that filter or transform along the way? Allowlist validator? JSON schema? ORM serializer?
11
+ - Is this code path actually called in production? Or is it a dead branch left from a refactor?
12
+ - If it's an internal service — is it exposed via a misconfigured ingress, reachable from the internet, accessible from a compromised pod? "Internal" is a policy, not a security boundary.
13
+ - Test: can you write a failing request/input that triggers the line? If you can write it in 5 minutes, an attacker can.
14
+
15
+ ---
16
+
17
+ ## Authz coverage: "Is every path checked?"
18
+
19
+ For an authz-critical operation (read user X, delete resource Y, invoke admin action):
20
+
21
+ - List every entry point (HTTP handler, gRPC method, queue worker, CLI command, background job). For each: is the check present?
22
+ - For HTTP: is the check in middleware (applies to all), or per-handler (easy to miss)? Grep for the check; count matches; count routes; compare.
23
+ - Does the check use *request-supplied* identity or *session-derived* identity? `X-User-Id: 42` header is not identity.
24
+ - Privilege escalation corner: can a user modify their own `role`, `tenant_id`, `permissions` via the same endpoint that updates their profile? (mass-assignment + authz = disaster.)
25
+ - Is authz re-checked after redirects / async continuations / token refreshes? Identity is not sticky across those.
26
+
27
+ ---
28
+
29
+ ## Data flow: "Does tainted data reach a dangerous sink?"
30
+
31
+ Source → sinks, both directions:
32
+
33
+ - **Top-down**: pick a source (request body, query string, file upload, DB read from a user-writable table). Grep how that variable flows. Does it reach a sink (SQL, shell, HTML, URL fetch, deserializer)?
34
+ - **Bottom-up**: pick a sink (every `subprocess.run`, every `db.raw`, every `innerHTML`). Trace backward. Is the input at the sink derivable from a source?
35
+ - Don't trust "it's validated upstream" without proof. Read the validator; check that the type after validation is strong enough (strings are weak, `UUID` is strong).
36
+ - Does the data go through serialization round-trips that could re-introduce metacharacters? JSON round-trip, URL-decoding at the wrong layer, base64 → string → SQL.
37
+
38
+ ---
39
+
40
+ ## Trust boundaries: "Where does untrusted become trusted?"
41
+
42
+ - Draw the boundary. What's on each side?
43
+ - At the boundary: is there validation (shape, type, range, allowlist)? Is there normalization (Unicode NFKC, lowercasing, path canonicalization)?
44
+ - Is the same boundary crossed more than once? (Controller → service → repo — does the repo re-validate, or trust the service?)
45
+ - Cross-service: does Service B trust Service A's payload? If A is compromised, what can B do?
46
+ - Cross-tenant: if a single process serves multiple tenants, where is the tenant id enforced? On every query? Or only at the top of the handler?
47
+
48
+ ---
49
+
50
+ ## Error paths: "What happens when this fails?"
51
+
52
+ - Every try/except / error branch: does it leak information (stack, internal IDs, DB errors) to the caller?
53
+ - Does the failure leave the system in a broken state (half-written file, partial DB row, orphaned session)?
54
+ - Does the failure log enough for you to debug a real incident? Generic "failed to process" without context is a blind spot.
55
+ - Are retries bounded? Does the retry code path itself re-authenticate, or reuse a possibly-stale token?
56
+
57
+ ---
58
+
59
+ ## Concurrency: "What happens with two of these at once?"
60
+
61
+ - Is there shared mutable state (module globals, singletons, caches, files)? Protected by a lock?
62
+ - Check-then-act races: `if not exists: create` — two requests can both pass the check. Use `INSERT ... ON CONFLICT` or transactions.
63
+ - Idempotency: can the client retry safely? Is there an idempotency key? Repeated payment, duplicate email, double-spend patterns.
64
+ - Async/await holding locks across `.await`: in Rust/Python, this deadlocks. In Go, it's fine but can cause fairness issues.
65
+
66
+ ---
67
+
68
+ ## Secrets lifecycle: "Where does this credential live, and who can read it?"
69
+
70
+ - Creation: how is it generated (entropy source)? Who knows it at creation time?
71
+ - Storage: env var, config file, KMS, DB, vault? File permissions?
72
+ - Transit: does it appear in logs, metrics, error messages, request bodies?
73
+ - Rotation: is there a story for rotating it? Automated or manual? What breaks during rotation?
74
+ - Revocation: if it leaks today, what's the time-to-revoke? Minutes, hours, or "we'd have to redeploy"?
75
+
76
+ ---
77
+
78
+ ## Input shape: "Can I break the parser?"
79
+
80
+ - Size: is there a max? What happens at the max+1? At 10×max?
81
+ - Depth: for JSON/XML/nested structures — max depth? Billion-laughs / deeply nested dicts can OOM.
82
+ - Encoding: UTF-8 vs UTF-16 vs Latin-1; BOM handling; surrogate pairs; null bytes in paths.
83
+ - Numeric: NaN, Infinity, -0, integer overflow, very large floats losing precision.
84
+ - Arrays: empty, one element, duplicate keys, sparse arrays, non-integer indices.
85
+
86
+ ---
87
+
88
+ ## How to record the outcome
89
+
90
+ For each finding that survives investigation, produce a one-line summary in this shape:
91
+
92
+ ```
93
+ [severity] [ruleId or ad-hoc tag] file:line — <one-sentence issue> — <one-sentence fix direction>
94
+ ```
95
+
96
+ Example:
97
+ ```
98
+ [high] IDOR /orders/:id (orders.ts:88) — handler loads order by URL id without comparing to session user — add owner check before load, 404 (not 403) on mismatch
99
+ ```
100
+
101
+ Feed these into the PR review comment or back to `rafter` for triage follow-up (`rafter/docs/finding-triage.md`).