Module 6 Release Notes — Bug Bounty Workspace
Full decision record: docs/adr/0006-bug-bounty-workspace-module.md.
Features added
Backend — the full bug-bounty-hunter workflow, layered read-through/ write-through on top of Modules 2-5 rather than duplicating their storage:
- Programs: CRUD, platform (HackerOne/Bugcrowd/Intigriti/YesWeHack/ Synack/Internal/Private/Custom), status, rules/severity-matrix/disclosure policy as free-form JSON/Markdown, tags.
- Scope Manager: scope items (Domain/Wildcard/URL/API/Mobile App/CIDR/
IP Range/ASN/Cloud Asset), auto-classification of any value or linked
Target against a program's scope rules (
IN_SCOPE/OUT_OF_SCOPE/UNKNOWN, OUT_OF_SCOPE always wins over a broader IN_SCOPE match), IPv4 CIDR/range matching implemented from scratch (IPv6 not supported — documented limitation). - Program Importer: HackerOne, Bugcrowd, Intigriti, Markdown, and JSON adapters behind one registry, normalizing a pasted platform export into a program + scope items in one request.
- Asset Inventory: targets aggregated at read time with Recon findings (technology/DNS/open ports/services/TLS), Vuln findings (count, critical count, risk score), Notes, Evidence (incl. screenshot count), and scope classification — no new storage, always fresh.
- Finding Lifecycle:
NEW → TRIAGED → VERIFIED → REPORTED → RESOLVED → CLOSED → ARCHIVED, withDUPLICATE/NEED_MORE_INFOside-branches;CLOSED/ARCHIVEDare terminal. - Bug Report Generator: one persisted report rendered into five platform-shaped templates (HackerOne/Bugcrowd/Intigriti/Markdown/HTML); export to PDF (via HTML)/Markdown/HTML/JSON/CSV.
- Report Draft Assistant: AI-generated executive summary, technical details, impact, risk, remediation, and references from a finding's data, reusing Module 5's provider/prompt-builder seam.
- Duplicate Detection: lexical (title Jaccard + exact field matches) and
semantic (pgvector cosine similarity via Module 5's
AiMemoryService) scoring, combined bymax(), threshold-filtered, top 10 results. - Payload Library: seed payloads (workspace-visible, not editable) plus per-workspace custom entries across 16 categories (XSS/SQLi/SSRF/SSTI/ XXE/IDOR/CSRF/LFI/RFI/RCE/Deserialization/JWT/GraphQL/CSP/CORS/Open Redirect), AI "explain this payload."
- Personal Knowledge Base: Markdown notes with an optional checklist, linkable to a project/target/finding/report.
- Bookmarks: save a target/finding/report/payload/note for quick access (polymorphic loose reference, no DB FK).
- Dashboard + Statistics: active programs, in-scope assets, pending reports, total bounty earned, recent findings, recent activity, success/ acceptance/duplicate rates, average severity, average time-to-triage/ resolve, monthly earnings, per-platform comparison.
- Calendar: submission deadlines, follow-ups, retests, disclosures.
- Notifications: deadline reminders (self-scheduling background poller, configurable lookahead/poll interval), program updates, AI recommendations — mark read / mark all read.
- Global Search: fans out across programs, findings, reports, payloads, and knowledge base notes.
- Events:
ProgramCreated,ProgramUpdated,FindingReported,ReportSubmitted,ReportAccepted,ReportRejected,BountyAwarded,ReportClosed— all recorded on the existing Activity Timeline via the same generic handler every other module already uses. - REST API: 11 controllers, ~50 endpoints, Swagger-documented, under
/bugbounty/*.
Security: workspace isolation + enumeration-safe 404s on every read
(same pattern as every prior module), soft deletes on Program/Finding/
Report/PayloadLibraryEntry/KnowledgeBaseNote, optimistic locking on
BugReport (new to this codebase — version-guarded updates, 409 on
conflict), rate limiting on AI-backed routes (program import, report draft
generation, payload explain — 20 req/min), full class-validator DTO
coverage.
Frontend — 11 pages under /bugbounty: Dashboard, Programs (list +
detail with scope manager/target linking/classify tool), Asset Inventory,
Findings (list + detail with stage transitions/duplicate check/create-report),
Reports (list + detail with AI draft/preview/export/submit, version-aware
save), Payload Library, Knowledge Base, Bookmarks, Calendar, Notifications,
Search. "Bug Bounty" promoted from the sidebar's "coming soon" section to a
real nav entry.
Bugs found and fixed
- Asset Inventory accepted an unvalidated
projectIdfilter, leaking targets across workspaces — fixed by validating it throughprojectsRepository.findByIdForWorkspace(). severityfields in the shared DTOs were typed as plainstringinstead ofVulnFindingSeverity— fixed by importing the real union type.BugReporthad notriagedAtcolumn, leavingaverageTimeToTriagedHourswith no source data — added the column, threaded it through the repository/mapper/DTO/handler.- Data leak:
PrismaPayloadLibraryRepository.list()'s duplicateOR:object keys silently dropped the workspace-visibility filter whenever a search term was supplied, returning every workspace's custom payloads — fixed by restructuring into anAND: [{OR: [visibility]}, {OR: [search]}]shape. - IDOR:
markRead(id)had no ownership check, letting any authenticated user mark any other user's notification as read — fixed by requiringuserIdand scoping the update by bothidanduserId. AiMemorySourceType's hand-maintained shared TS union was missing the three Module 6 source types the Prisma schema already had — fixed by syncing them.
Known limitations
- Asset Inventory's per-request join has no caching layer; large workspaces (hundreds of targets, thousands of findings per program) would benefit from a materialized view — not built here, flagged as a follow-up.
- Statistics reads at most a workspace's most recent 1000 reports/findings
per repository
list()call rather than a SQL aggregate. - IPv6 CIDR/range scope matching is not implemented.
- PDF export has no dedicated server-side renderer; it returns the report's
HTML content with
mimeType: "text/html"for the client to convert.
Testing
Unit tests added for the highest-value pure logic and handler behavior:
scope classification (classify-scope-value.util.spec.ts), duplicate
lexical scoring (duplicate-lexical-score.util.spec.ts), finding
stage-transition guards including the terminal-stage and DUPLICATE-requires-
duplicateOfId rules (bugbounty-finding-lifecycle.commands.spec.ts), bug
report optimistic locking and status-transition event publishing
(bug-report-lifecycle.commands.spec.ts), and all five report template
renderers including HTML-escaping of user content
(bug-report-template-renderer.spec.ts).
Build/lint/typecheck were run against the whole apps/web package in-session
(clean). apps/api's full project typecheck and the Jest suite could not be
run to completion in this sandbox — the sandbox has no network access to
Prisma's binary CDN (so prisma generate can't run) and apps/api's
project-wide tsc run exceeds the sandbox's 45s per-command budget; the
pre-existing ts-jest/Jest version mismatch that blocks all Jest execution
in this sandbox (confirmed against an existing, unrelated Module 4 spec —
not something this module's changes caused) is unresolved here. Run
pnpm build && pnpm lint && pnpm check-types && pnpm test from the repo root
before merging — see the Completion Rule in the Module 6 task list.