# hackerone-report

Draft and file a HackerOne report in the browser, with a proof-of-concept package and demo-video notes. Use to submit or prepare a bug-bounty report.

- **Kind:** skill
- **Source:** https://github.com/forefy/.context
- **Page:** https://forefy.com/skills/980a4af9-de60-41b1-bedf-7aa1d99be9fa
- **API (JSON + files):** https://forefy.com/api/asr/980a4af9-de60-41b1-bedf-7aa1d99be9fa

---

## SKILL.md

---
name: hackerone-report
description: Draft and file a HackerOne report in the browser, with a proof-of-concept package and demo-video notes. Use to submit or prepare a bug-bounty report.
---

# Filing a HackerOne report

Drive a HackerOne vulnerability submission end to end: verify it's worth filing, write it up concisely, build a reproducible PoC with a video-ready README, fill the submission form in the browser, and hand the irreversible steps back to the user.

## Non-negotiable safety rules

These are hard stops. They protect the user's account and their Signal.

1. **Never enter credentials or 2FA codes.** When the form gates on login, take a screenshot, tell the user to sign in themselves, and wait. Suggest they tick "Remember me for 2 weeks" (HackerOne sessions drop mid-flow otherwise).
2. **Never click the final "Submit Report".** It is an irreversible publish and it spends one of the user's reports. Fill everything, then hand off: the user reviews and submits. State this explicitly up front.
3. **Never attach files the user didn't ask you to**, and don't fabricate PoC output. The in-app browser can't drive the native file picker anyway - the user attaches the zip and the video.
4. **Filing is per-user consent.** Draft freely; the act of submitting is the user's.

## Phase 0 - Dedup pre-flight (do this FIRST, every time)

The most expensive mistake is re-filing a finding the program already closed. It wastes a report and dents Signal. Before drafting anything:

- **Search the local findings tree** for prior work on the same root cause / sinks / code paths. Look especially in any `duplicates/` folder and for filenames encoding a resolution: `Informative-*`, `Duplicate-*`, `NA-*`, `Resolved-*`. A file named `Informative-1-<x>.md` means the program already closed `<x>` as Informative.
- **Compare code locations, not just titles.** Grep both the candidate writeup and prior reports for the exact files/functions/sinks cited. If they overlap, it's the same finding regardless of new framing. (A "new vector" that strengthens the *entry* but reaches the *same sink the program already judged* is still a duplicate.)
- **Offer to check the live program state:** open HackerOne → *My Reports*, search a keyword from the finding, read the actual close reason/comment.
- If it's a dup: **say so plainly and recommend not filing.** Options: don't file; comment/appeal on the *existing* report instead of opening a new one; hold reports for something novel. Only proceed on the user's explicit go-ahead.
- Also surface program constraints visible on the submit page: **"Trial Reports Remaining: N"** and any **Signal Requirement** - a low Signal can block future submissions, so accuracy matters more than volume.

## Phase 1 - Write the report (concise)

Use `references/report-template.md`. House style:

- **Plain, direct, first person** ("we found this field is forgeable"), not marketing prose.
- **State each fact once.** The same "new vector / defeated mitigation" point tends to sprawl across Summary, Component, Steps, and Impact - keep it in Summary + the Steps variant, and don't re-litigate it in Impact.
- **No em dashes** if the user prefers plain hyphens; use spaced hyphens ` - ` and split run-ons into sentences.
- Sections: Summary → Version/Affected → Component (vulnerable code paths) → Steps To Reproduce → Supporting Material → Impact → Suggested Fix.
- **Title** goes in its own field (max ~150 chars): `<vuln type> via <mechanism> (<feature/component>, <version/context>)`. Don't repeat the title as the first line of the Description body.

## Phase 2 - PoC package + video-ready README

Goal: a self-contained folder the triager can run and the user can film. Use `references/poc-readme-template.md`.

- **One command per step, copy-paste, in order:** prerequisites check → environment setup → baseline (the thing that is denied) → exploit → the money-shot success → a control that proves the mechanism → teardown.
- **The money shot** is a before/after: the *same* request denied, then succeeding, with only the exploited variable changed. That's what the video should capture.
- **Actually run the exact README blocks on a clean environment before shipping.** Repro commands that work in your head often fail copy-paste (auth/credential precedence, working-directory resets, tool flags that don't override config). Fix them until a fresh run reproduces.
- Prefer a few transparent commands over a big opaque `.sh`. If shared shell state is the only reason for a script, capture it in a tiny helper function inside the README instead.
- Ship: `README.md` (the walkthrough), the exploit inputs, an annotated pointer to the vulnerable source lines, a non-interactive runner, and any plumbing clearly labeled "not part of the vulnerability". Zip it; reference it in the report as `poc.zip`. The user records `poc.mov` and attaches both.

## Phase 3 - Browser: reach the submission form

Use the in-app Browser (`mcp__Claude_Browser__*`) or Claude-in-Chrome. Gotchas learned:

- Navigate to `hackerone.com/<program>`. The submit entry is **"Submit without Report Assistant"** (full manual form). Its href looks like `/<program>/reports/new?type=team&report_type=vulnerability`.
- **Do NOT deep-link that URL** - it's a client-side SPA route and returns "Page not found" on direct navigation. **Click the link on the program page instead.**
- Expect a **login/2FA gate** → hand off to the user (safety rule 1). After they sign in, the program page may need a reload.
- Sessions expire mid-flow; if the form empties or bounces to sign-in, have the user re-auth with "Remember me".

## Phase 4 - Fill the form

The manual form is a numbered flow. Prefer `read_page` refs over pixel coordinates (the pane rescales screenshots and raw-coordinate clicks miss). Use `form_input` for text fields - it's reliable.

| # | Field | How |
|---|---|---|
| 1 | **Asset** | Type in the asset search box to filter, then click the match. For a source-code asset, search its repo slug (e.g. an `<org>/<repo>` GitHub asset tagged "Eligible for bounty") and pick the exact program-listed entry - don't assume a specific project. If the inline list stays open and eats scroll, clear the search text / press Escape to collapse it. |
| 2 | **Weakness (CWE)** | Type a keyword (e.g. `authorization`) to filter, pick the CWE (e.g. Improper Authorization CWE-285). Then set the **cluster/subcategory** dropdown next to it (e.g. *Access Control*). Selecting the CWE is preserved even if the list then filters empty. |
| 3 | **Severity (CVSS)** | "Submit report with severity" → CVSS 3.0 calculator. Set each metric button by ref. Set the clearly-correct metrics yourself; **leave a genuinely judgment-call metric (usually Scope) for the user**, and show them both resulting scores (e.g. Scope:Unchanged→High vs Scope:Changed→Critical). Read the live "Score" readout back to them. |
| 4 | **Title** | `form_input` the title string (≤150 chars). |
| 4 | **Description** | `form_input` the report body (Summary → … → Suggested Fix), Markdown. Drop the leading `# Title` line - the Title field holds it. |
| 4 | **Impact** | Separate required field. `form_input` the Impact paragraph only. |
| 4 | **Attachments** | User drags in `poc.zip` + `poc.mov` (you can't drive the native picker). Optionally suggest renaming the zip to match what the report references. |

After filling, offer to click **Preview** on the Markdown fields so the user can eyeball rendering. Verify the "Review and Submit" panel shows the right Title/Asset.

## Phase 5 - Hand off

Summarize the filled state as a table (Asset / Weakness / Severity / Title / Description / Impact = done). List what remains and that it's the user's: attach zip, record+attach video, decide any judgment-call CVSS metric, review, **click Submit**. Re-state that you won't click Submit and won't loop on the blocked login.

## References

- `references/report-template.md` - the concise finding writeup skeleton with all section headings.
- `references/poc-readme-template.md` - the video-ready copy-paste reproduction README pattern.

## references

```

```

## references/poc-readme-template.md

# Video-ready PoC README pattern

The README is a script for a user-filmed demo: every block copy-pastes in order, and the reader can narrate over it. One command per step. Verify the exact blocks on a clean environment before shipping - copy-paste repros fail in ways your mental model won't (auth/credential precedence, working-directory resets between shells, CLI flags that don't override config files).

Structure:

```
# <Finding title> (PoC)

<2-3 sentence plain-language statement of the bug and the win, and what's affected/default-on.>

Everything below is copy-paste, one block at a time.

## Prerequisites
<one command that checks the tools are present>

## Step 0 - Set up a throwaway environment
<create the disposable target (docker/VM/local sandbox/etc.), fully self-contained>
<apply the scenario: victim asset + attacker principal with minimal grants>

## THE PROOF - N commands
<any one-time setup for acting AS the attacker identity, with a note on WHY
 it's needed (e.g. a token-only client, because --token doesn't override a
 cert-based config). Wrap repeated long invocations in a tiny helper fn.>

1. <baseline: the request that is DENIED with the honest identity>     # -> DENIED
2. <the forge/abuse step; show the tainted state>                      # -> forged X
3. <the same request, now SUCCEEDING via the exploit>                  # -> <secret/flag>

<one line: command 1 denied, command 3 succeeded, only <var> changed. Then how it scales.>

## Teardown
<delete the throwaway environment>

## Optional extras
- run-all.sh    - the above non-interactively, for a hands-off take
- <variant>.sh  - a distinct stronger/cheaper variant (kept optional)
- <source>      - annotated excerpt of the vulnerable lines
- <scenario>    - the attacker's exact minimal role/permission config
```

Principles:

- **The money shot is the before/after.** Command 1 (denied) and command 3 (succeeds) differ only by the exploited variable. That contrast is what the video sells.
- **Prefer transparent commands over an opaque script.** If shared shell state (a captured token, a URL) is the only reason for a script, put it in a small helper function in the README and keep each proof line short and readable.
- **Label plumbing.** Anything that's convenience, not vulnerability, says so - triagers must not mistake it for the bug.
- **Attach, don't inline secrets.** The user records `poc.mov`; the zip carries the runnable files. The report references both.

## references/report-template.md

# HackerOne report writeup template

Fill each section. Keep it plain and first-person. State each fact once. The `# Title` line is for the Title field only - do not paste it into the Description body.

---

# <Vuln type> via <mechanism> (<feature/component>, <version or context>)

## Summary

What the affected feature is supposed to guarantee, in one or two sentences. Then the bug: what is trusted that shouldn't be, and what an attacker does with it, ending in the concrete win (what they read/write/become). If there's a cheaper or stronger variant, state it once here.

## <Product> Version

Where it was reproduced (exact version + distribution + how it was run) and whether it was also confirmed by source review (repo @ commit/date).

Affected: which versions/configurations/feature-gates. Note default-on vs opt-in and the maturity (Alpha/Beta/GA) of every relevant gate.

## Component Version

The vulnerable component + version, then a bullet per code location with a one-line role:

* `path/to/file.go` - what's wrong here (the missing check / the bad trust).
* `path/to/sink.go` - where the tainted value is consumed as a security decision.
* (list every sink - a complete sink census pre-empts the "is this the only place?" question.)

## Steps To Reproduce

"A self-contained PoC is attached; its `README.md` drives this step-by-step (verified end-to-end on <env>)."

1. **Environment** - the exact setup command(s).
2. **Scenario** - apply the scenario config (or equivalent): the victim asset + the attacker principal with ONLY the minimal grants (spell them out; note "no admin, no direct access").
3. **Baseline** - the action that is correctly denied with the honest identity.
4. **Exploit** - the forge/abuse command, with the exact payload inline.
5. **Confirm** - show the tainted/forged state (e.g. `whoami` output).
6. **Escalate** - the money shot: the previously-denied action now succeeds, in plaintext.
7. **Control** - a near-identical attempt that still fails, proving the exploited variable (not a broad grant) is the deciding factor.
8. **Scale** (if applicable) - how it generalizes (all nodes / all tenants / etc.).
9. **Teardown** - tear down the throwaway environment.

Optional variant: one short paragraph, only if it adds a distinct precondition/mitigation-defeat - not a restatement.

## Supporting Material/References

* **poc.zip** - one line on what running it proves; then a compact inline list of the key files and their roles (scenario, payload, runner, annotated source, plumbing-not-part-of-the-vuln).
* **poc.mov** - one line describing the recording's arc (baseline denial → exploit → success → control).

## Impact

Who the attacker is (realistic starting position), what they end up able to do, and why it breaks the security boundary the feature advertises. One tight paragraph. Don't re-derive the mechanism here.

## Suggested Fix

The concrete change(s) that close it, mapped to the code locations above. One or two sentences.

