EVIDENCE HYGIENE — PoC Capture & Redaction Discipline
Use this skill BEFORE capturing any screenshot, exporting any HAR, or attaching any evidence to a bug-bounty submission. It catches the most common evidence-hygiene mistakes that cause cookies to leak, PII to be shared without consent, or screenshots to be unsuitable for triage.
The core principle: Bug-bounty evidence is meant to convince a triager. Anything beyond that — live cookies, real-user PII, internal trace IDs that aren't useful — should not be in the evidence.
1. Two Categories of Sensitive Data
Every PoC artifact (screenshot, HAR, raw HTTP request, terminal transcript) potentially contains data that needs different treatment.
| Category | Examples | Treatment |
|---|---|---|
| Your-account secrets | Session cookies, OAuth tokens, refresh tokens, API keys | Always redact. Even in private bug-bounty platform attachments. Your account, your session — protect it. |
| Other users' PII | Real names, emails, phone numbers, addresses, profile photos, account IDs | Redact unless explicitly demonstrating cross-account impact. Even then, mask faces and minimize the data you display. |
| Triager-useful metadata | Trace IDs (x-datadog-trace-id), request IDs, server timestamps, your test account UID/email, GraphQL operation names, response shapes | Leave visible — these help the triager correlate to logs and reproduce. |
| Test-account passwords (limited use) | Throwaway passwords on a test account (e.g., Testing@5678) | Acceptable in screenshots if you rotate immediately after submission so the value shown is dead. Don't leave real-use passwords in evidence. |
2. Cookie Redaction Protocol
2.1 What must be masked
The session cookie value is the highest-value secret in any PoC. Mask:
- The session cookie (
authn,session,sid,__Secure-id, etc. — name varies per target) csrf-tokenif it's bound to your sessionAuthorizationheaders (Bearer tokens, JWT)Cookierequest header values for any session-bearing cookieSet-Cookieresponse header values for any session-bearing cookie
2.2 What's safe to leave visible
- Cloudflare cookies (
__cf_bm,_cfuvid) — these are bot-management, not session-bearing - Analytics cookies (
ajs_anonymous_id,_ga) - Trace correlation IDs (
x-datadog-trace-id,x-request-id) - Server / framework headers (
Server: cloudflare,X-Frame-Options) - Your test account email/UID (per Bugcrowdninja alias section in
bugcrowd-reporting)
2.3 Redaction methods (ranked by practicality)
Method A — Don't capture the cookies in the first place (preferred when possible)
- For DevTools Console PoCs: use
credentials: 'include'so the browser sends cookies automatically. Console output won't echo the cookie. Screenshot the Console output, never the Network tab Headers panel. - For Burp Repeater PoCs: drag the bottom request/response panel divider DOWN to hide the request body before screenshotting. Capture only the Results table for Intruder runs.
Method B — Black-bar in image editor (when capture inevitably includes cookies)
- macOS: Open screenshot in Preview → Tools → Annotate → Rectangle → set fill color to black → drag rectangle over the cookie value → save
- Windows: Use Snip & Sketch's annotation tools or any image editor (Paint.NET, etc.)
- Burp itself: in Burp's Proxy → Match and Replace, you can pre-emptively redact cookie values to placeholder strings before screenshotting
Method C — Find/replace in raw text (for HAR files, terminal transcripts)
- See §4 for the jq commands
2.4 Pre-screenshot checklist
Before clicking Capture:
[ ] Network tab Headers panel is collapsed or out of frame
[ ] Burp's Request panel is hidden behind the divider drag
[ ] No "Copy as cURL" output is visible on screen
[ ] DevTools Application → Storage → Cookies tab is closed
[ ] Browser URL bar doesn't show a session token in query string (rare but possible)
After capturing:
[ ] Open the screenshot at full resolution before saving
[ ] Search for the session cookie name substring in any visible text — if present, redact
[ ] Search for the literal first 6 chars of your cookie value — if present, redact
[ ] Compare to the previous PoC screenshot in the same engagement — same redaction discipline
3. PII Black-Bar Protocol
When a PoC necessarily exposes another user's data (e.g., demonstrating IDOR by showing the victim's email in an attacker-session response), redact the actual PII even in private attachments.
3.1 What to mask (other-user data)
- First name, last name (full or partial)
- Email address (mask the local part; can leave domain if non-identifying)
- Phone number (mask the last 7 digits, optionally leave country code)
- Physical address (mask everything below city)
- Date of birth (mask the year, optionally the month)
- Government IDs (SSN, passport — mask everything)
- Profile photos / face images (black-bar the face entirely)
- Account IDs that the user could correlate to public profiles
3.2 What to leave visible (proves the bug, not the user)
- The fact that the field was returned (the JSON key name)
- The shape / type of the field (
"first_name": "<REDACTED>") - Your own (attacker session's) UID / email — this proves cross-account
- The endpoint URL and request method
- The trace ID
3.3 Worked example — IDOR PoC body
Bad (leaks victim's full PII):
{"data":{"contact":{"first_name":"Nadene","last_name":"Afton","email":"nadene.afton@example.com","phone":"+1-555-867-5309"}}}
Good (proves the bug, masks the PII):
{"data":{"contact":{"first_name":"<REDACTED — real first name>","last_name":"<REDACTED — real last name>","email":"<REDACTED>@example.com","phone":"<REDACTED>"}}}
In screenshot form, black-bar each value with a rectangle annotation labeled "REAL PII REDACTED" if there's space.
3.4 In the report body
Reference the redaction explicitly:
## Proof of Concept
The screenshot below demonstrates the IDOR. The attacker session (uid 12345678) successfully retrieves the victim's profile data (uid 99887766). **Real PII fields in the response are masked with black rectangles to limit unauthorized exposure of victim data, per responsible-disclosure hygiene.** The unredacted response is available privately on request.
This signals the triager that you're disciplined and gives them a clear path to the unredacted version if they need it for verification.
4. HAR File Sanitization
HAR (HTTP Archive) files are JSON dumps of network traffic with full request/response bodies and headers. They include cookies, auth tokens, and any PII that was in transit.
4.1 Generate the HAR
Chrome DevTools → Network tab → right-click anywhere in the request list → "Save all as HAR with content"
4.2 Sanitize before attaching
Use jq to strip sensitive headers. Save this as a shell function or one-liner you can re-use:
sanitize_har() {
local input="$1"
local output="${1%.har}.sanitized.har"
jq '
.log.entries |= map(
(.request.headers |= map(
if .name | ascii_downcase | IN("cookie", "authorization", "x-csrf-token") then .value = "<REDACTED>" else . end
)) |
(.response.headers |= map(
if .name | ascii_downcase | IN("set-cookie") then .value = "<REDACTED>" else . end
)) |
(.request.cookies |= map(.value = "<REDACTED>")) |
(.response.cookies |= map(.value = "<REDACTED>"))
)
' "$input" > "$output"
echo "Sanitized: $output"
}
Usage:
sanitize_har /path/to/exported.har
# Output: /path/to/exported.sanitized.har
4.3 Verify before attaching
# Check that no Cookie or Authorization values are leaking
grep -i 'authn\|"cookie"\|authorization' /path/to/exported.sanitized.har | head -20
If you see your real cookie value in the output, the sanitization missed something — fix the jq