diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 0000000..6245a40 --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1,95 @@ +# CLAUDE.md + +Guidance for Claude when working in this repository (`hacdias/webdav`). + +## Handling security advisories + +Advisory state lives on GitHub and is driven with the `gh` CLI: `triage → draft → published`, plus `closed`. Reports are routed as per [SECURITY.md](../SECURITY.md); only `5.x` is supported. + +### 1. Fetch + +```bash +# List by state (also: published, draft, closed) +gh api '/repos/hacdias/webdav/security-advisories?state=triage&per_page=100' \ + --jq '.[] | {ghsa_id, severity, summary, state}' + +# Full report for one advisory +gh api /repos/hacdias/webdav/security-advisories/GHSA-xxxx-xxxx-xxxx \ + --jq '.summary, "---", .description' +``` + +Always pull the published and remaining triage sets too, to dedup against. + +### 2. Verify — do NOT trust the report text + +Read the source at HEAD and reproduce the claim; a failing `makeTestServer` case is better evidence than reading the matcher. Reach one verdict per advisory: + +- **CONFIRMED** — defect exists at HEAD. Quote the exact `file:line`. +- **FIXED** — already patched; find the fix commit and the release carrying it. +- **FALSE / NOT APPLICABLE** — claim is wrong, or targets a different project. +- **NOT EXPLOITABLE** — pattern exists but no code path reaches the precondition. +- **DUPLICATE** — of a published advisory, or of another triage advisory. + +Common traps: + +- **"Incomplete fix of a prior advisory."** Read the original fix commit and confirm the specific sibling path is still unguarded. `GHSA-chxv-mvjv-f92j` already cleans paths in `newRequest` and matches trailing-slash rules against the bare collection. +- **Wrong project.** Confirm the cited files, symbols, and options exist here — reports sometimes describe a fork or another WebDAV server. +- **Containment vs authorization.** `golang.org/x/net/webdav` applies `slashClean` and keeps requests inside the served root, so "traversal out of `directory`" is usually not the defect. The real class is the authorization layer disagreeing with the filesystem layer about which file a request names. +- **No `users:` means no authentication, by design** — it warns at startup. Not a vulnerability, but it changes the privilege precondition. +- **Overlapping reports.** Several triage advisories may share one root cause: consolidate into one, close the rest as duplicates. + +Record per advisory: verdict, `file:line` evidence, preconditions (default config? needs `directories:`? platform-specific? auth required?), disposition. + +### 3. Severity + +Set a CVSS v3.1 vector — GitHub derives the score and severity from it, overriding the plain `severity` field. Encode the real preconditions so the band is defensible: a required configuration or platform (case-insensitive filesystem, `directories:`) is **AC:H**; needing an account is **PR:L**. Rate the base case as a config with a `users:` block, and note the unauthenticated vector in the body when it is materially worse. Don't let an incomplete-fix follow-up outrank its parent. + +```bash +gh api -X PATCH /repos/hacdias/webdav/security-advisories/GHSA-xxxx-xxxx-xxxx \ + -f cvss_vector_string='CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N' \ + --jq '{ghsa_id, severity, score: .cvss.score, vector: .cvss.vector_string}' +``` + +### 4. Rewrite the title and body + +The title is `summary`: concise and sentence-case, stating the vulnerability class then the mechanism, e.g. `Authorization bypass: path rules can be evaded with dot segments or a bare collection name`. + +Rewrite `description` into the sections below, reusing the reporter's own wording where it is accurate. Drop the greeting and anything step 2 disproved. Use `###` headings, keep this order, omit what doesn't apply. Keep the maintainer's voice — first person belongs only in quoted PoC steps. + +| Section | Contents | +| ------------------ | -------------------------------------------------------------------------------------------------------------- | +| `Summary` | The defect and its root cause, naming the file and function, quoting the pre-fix code. | +| `Impact` | Who can exploit it and what they get. State what is *not* affected. | +| `Proof of concept` | Config and steps trimmed to the essentials, with observed results. | +| `Patches` | `Fixed in **vX.Y.Z**. Upgrade to that version or later.` plus what the fix does and why it sits where it does. | +| `Workarounds` | What the operator can do themselves. `None.` if nothing helped, saying why. | +| `Out of scope` | What the report claimed that is deliberately not treated as a vulnerability, and why. | +| `References` | Related issues, commits, published advisories. | + +Send it as a file so the Markdown survives shell quoting: + +```bash +jq -Rs '{description: .}' desc.md \ + | gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx --input - +``` + +### 5. Affected versions + +The package is always `{ecosystem: "go", name: "github.com/hacdias/webdav/v5"}`. `vulnerable_version_range` ends at the last release before the fix; add a lower bound when the defect was introduced in a known version, confirming with `git log -S` and `git tag --contains`. `patched_versions` is the release carrying the fix. + +```bash +printf '%s' '{"vulnerabilities":[{"package":{"ecosystem":"go","name":"github.com/hacdias/webdav/v5"},"vulnerable_version_range":">= 5.10.0, <= 5.14.1","patched_versions":"5.14.2","vulnerable_functions":[]}]}' \ + | gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx --input - +``` + +### 6. Move state + +```bash +gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx -f state=draft # ready to publish +gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx -f state=closed # duplicate / N-A / not-exploitable +``` + +- **CONFIRMED** → fix, release, set `patched_versions` → draft, then publish once the release is out. +- **DUPLICATE / NOT APPLICABLE / NOT EXPLOITABLE** → closed. + +The REST API cannot post advisory comments. Replies to reporters must be posted manually in the UI — draft the text for the maintainer.