Bug Bounty Page React template for Tailwind CSS v4
v1.0.0Added in 1.9.0
A bug bounty program page: rewards by severity with a CVSS reward estimator, scope, rules and safe harbor, a hall of fame and a report form.
The hero rises in once beside a drawn triage terminal whose status badge flips from New to Triaged to a $7,500 bounty while the log ticks off (still under reduced motion and in thumbnails); the PGP chip copies the key fingerprint. Submit a report scrolls to the form and focuses its title; chips under the stats jump to each section, and the four program numbers roll up once when they scroll into view. The rewards table becomes cards below 768px. Estimate your reward: pick the asset tier, five simplified CVSS 3.1 inputs and the report quality on segmented controls (arrow keys move within each) and the score, severity badge, vector string and USD range update live and are announced. Scope tabs switch between in-scope assets (a table that becomes cards on phones) and out-of-scope findings. The year control filters the leaderboard; every disclosed report is one link. The report form validates on submit and moves focus to a GOV.UK style error summary whose links focus each field; attachments take a click or a drop, list names and sizes, flag files over the limit and can be removed; the submit button spins while onSubmitReport runs, then a success panel shows the report ID with a copy button and the next steps. The closing band copies security@acme.com.
Built with
The sections this page is made of. In the full-screen preview, hold Alt to outline each one on the page.
Add to a project
npx wingo-ui@latest add bug-bounty-pagePro item: the CLI needs a Pro account. See plans
Usage
Import BugBountyPage from @/components/templates/bug-bounty-page.
// app/(marketing)/security/bug-bounty/page.tsx
"use client"
import Link from "next/link"
import { BugBountyPage } from "@/components/templates/bug-bounty-page"
export default function BugBountyRoute() {
return (
<BugBountyPage
linkComponent={Link}
onSubmitReport={async ({ files, ...values }) => {
const body = new FormData()
body.append("report", JSON.stringify(values))
files.forEach((file) => body.append("files", file))
const response = await fetch("/api/security/reports", { method: "POST", body })
if (!response.ok) throw new Error("Could not submit the report")
const { id } = (await response.json()) as { id: string }
return id
}}
/>
)
}Props
designdefault"classic""classic" | "terminal" | "minimal"The whole page's look. classic follows the layout props; terminal: a dark monospace page in both themes with $-prefixed eyebrows, a green dotted backdrop, hairline panels, dashed section rules, mono figures and a soft closing band; minimal: a transparent header, a centered hero without the terminal, outlined panels, no bands, a plain closing band and a simple footer. The *Props overrides still win.
statsdefault"BUG_BOUNTY_STATS"BugBountyStat[]{ id, value, decimals?, prefix?, suffix?, label } numbers under the hero; they roll up once in view.
rewardsdefault"BUG_BOUNTY_REWARDS"BugBountyReward[]{ severity, min, max, cvssMin, cvssMax, examples } rows of the rewards table, amounts in USD.
assetTiersdefault"BUG_BOUNTY_ASSET_TIERS"BugBountyAssetTier[]{ tier, label, description, multiplier } tiers; the estimator scales the range by the multiplier.
assetsdefault"BUG_BOUNTY_ASSETS"BugBountyAsset[]{ id, name, type, tier, notes } in-scope assets, also the form's asset choices.
outOfScopedefault"BUG_BOUNTY_OUT_OF_SCOPE"BugBountyExclusion[]{ id, title, description } findings that are out of scope.
rulesdefault"BUG_BOUNTY_RULES"BugBountyRule[]{ id, title, description } numbered rules of engagement.
timelinedefault"BUG_BOUNTY_TIMELINE"BugBountyTimelineStep[]{ id, title, sla, description } steps of the disclosure timeline.
researchersdefault"BUG_BOUNTY_RESEARCHERS"BugBountyResearcher[]{ handle, country, points, reports, year } leaderboard entries; country is an ISO code shown as text.
reportsdefault"BUG_BOUNTY_REPORTS"BugBountyDisclosedReport[]{ id, title, severity, bounty, disclosedAt, researcher, asset, href } recently disclosed reports; disclosedAt is an ISO day.
vulnerabilityTypesdefault"BUG_BOUNTY_VULNERABILITY_TYPES"BugBountyOption[]{ value, label } choices of the Vulnerability type select.
programdefault"BUG_BOUNTY_PROGRAM"BugBountyProgram{ email, pgpFingerprint, pgpHref, securityTxtHref, policyHref, reportIdPrefix, firstReportNumber }.
scenedefault"BUG_BOUNTY_SCENE"BugBountySceneThe strings of the hero's triage terminal: { window, command, reportId, fields, cvss, phases, log }.
faqdefault"BUG_BOUNTY_FAQ"FaqItem[]Questions and answers for the FAQ section.
labelsdefault"DEFAULT_BUG_BOUNTY_PAGE_LABELS"Partial<BugBountyPageLabels>Every visible string: headings, table headers, estimator options, form fields and errors, success copy.
heroLayoutdefault"split""split" | "centered"The hero copy beside the triage terminal, or centered over it. Applies to the classic design.
defaultScopeTabdefault"in""in" | "out"The scope tab open on load.
defaultYeardefault2026numberThe leaderboard's year on load; a year without entries falls back to the newest year in researchers.
maxFileSizedefault10numberThe largest attachment in megabytes; bigger files are flagged and block the submit.
maxFilesdefault5numberHow many attachments a report can carry.
onSubmitReport(values: BugBountyReportValues) => (string | void | Promise<string | void>)Called with { title, asset, vulnerabilityType, severity, steps, impact, files, email, agree } once the form is valid. A returned promise keeps the button loading, a string it resolves to becomes the report ID and a rejection shows labels.failed. Without it the form waits 900 ms and shows the next ID (ACME-H1-2026-0412).
showStatsdefaulttruebooleanThe program numbers under the hero.
showJumpLinksdefaulttruebooleanThe row of section chips.
showRewardsdefaulttruebooleanThe rewards section.
showEstimatordefaulttruebooleanThe Estimate your reward calculator inside the rewards section.
showScopedefaulttruebooleanThe in scope / out of scope tabs.
showRulesdefaulttruebooleanThe rules of engagement and the safe harbor callout.
showTimelinedefaulttruebooleanThe disclosure timeline.
showHallOfFamedefaulttruebooleanThe leaderboard section.
showReportsdefaulttruebooleanThe recently disclosed reports beside the leaderboard.
showSubmitdefaulttruebooleanThe report form.
showFaqdefaulttruebooleanThe FAQ section.
showCtadefaulttruebooleanThe closing band with the security email.
alternatedefaulttruebooleanBands on every other visible section, in the bandBackground look. Applies to the classic design.
backgrounddefault"grid""plain" | "soft" | "glow" | "aurora" | "grid" | "dots"The main background: plain is the bare page color; the others tint the page and add a glow, an aurora, a grid or dots over the first screen. A design picks its own unless you set one. Classic uses grid, terminal dots, minimal plain.
backgroundColordefault"oklch(0.62 0.14 275)"stringThe tint and glow color of the main background; the terminal design uses a terminal green unless you set one.
bandBackgrounddefault"muted""muted" | "tinted" | "gradient" | "dots"The secondary background of the alternating bands. Cards, fields and tiles inside a band are lifted one step above it, so they never share its color.
bandColordefault"oklch(0.62 0.14 275)"stringThe tint of tinted and gradient bands; defaults to backgroundColor.
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"Icon tiles, timeline nodes, the top three ranks, the safe harbor badge and the estimator's segmented controls. Severity colors stay fixed.
ctaTonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"Get started, both Submit a report buttons and the form's submit; brand is the marketing orange.
radiusdefault"md""none" | "sm" | "md" | "lg" | "full"The corners of the form fields, the scope tabs and the segmented controls.
headerdefaulttruebooleanThe marketing header; off inside a site layout.
footerdefaulttruebooleanThe marketing footer.
headerPropsPartial<MarketingHeaderProps>Passed to MarketingHeader.
footerPropsPartial<MarketingFooterProps>Passed to MarketingFooter.
heroPropsPartial<HeroSectionProps>Overrides for the HeroSection (media, background...).
faqPropsPartial<FaqSectionProps>Overrides for the FaqSection (layout, variant...).
ctaPropsPartial<CtaSectionProps>Overrides for the closing CtaSection (variant, actions...).
animateIndefaulttruebooleanThe hero rises in, the numbers roll up and the triage terminal plays; false keeps everything still (thumbnails). Reduced motion always does.
localedefault"en-US"stringIntl locale for the USD amounts, numbers, file sizes and dates (shown in UTC).
linkComponentdefault"<a>"(props: LinkComponentProps) => ReactNodeThe router link for every link on the page (next/link in an app).
classNamestringClasses for the root.
classNamesPartial<Record<BugBountyPageSlot, string>>Classes for header, hero, stats, jump, rewards, estimator, scope, rules, safeHarbor, timeline, hallOfFame, leaderboard, reports, submit, form, success, faq, cta and footer.
Parts
cvssScore
functioncvssScore({ attackVector, attackComplexity, privileges, userInteraction, impact }): the CVSS 3.1 base score with scope unchanged and one impact level for C, I and A.
cvssSeverity
functioncvssSeverity(score): critical, high, medium, low, or null for 0.
estimateReward
functionestimateReward(reward, score, quality, multiplier): the { low, high } USD estimate the calculator shows, rounded to $50.
BUG_BOUNTY_PAGE_SAMPLE
constantAll the sample content in one object.
BUG_BOUNTY_STATS
constant$1.4M paid, 612 researchers, 9 hours to first response, 11 days to bounty.
BUG_BOUNTY_REWARDS
constantCritical $10,000 to $30,000, High $3,000 to $10,000, Medium $750 to $3,000 and Low $150 to $750.
BUG_BOUNTY_ASSET_TIERS
constantTier 1 (100%), Tier 2 (60%) and Tier 3 (30%).
BUG_BOUNTY_ASSETS
constantapp.acme.com, api.acme.com, the desktop and mobile apps, the CLI and the browser extension.
BUG_BOUNTY_OUT_OF_SCOPE
constantTen out-of-scope finding types.
BUG_BOUNTY_RULES
constantEight rules of engagement.
BUG_BOUNTY_TIMELINE
constantReport, Acknowledge, Triage, Fix, Bounty and Disclose with their promises.
BUG_BOUNTY_RESEARCHERS
constantLeaderboard entries for 2024 to 2026.
BUG_BOUNTY_REPORTS
constantSix recently disclosed reports.
BUG_BOUNTY_VULNERABILITY_TYPES
constantThe Vulnerability type choices.
BUG_BOUNTY_PROGRAM
constantThe security email, PGP fingerprint, links and report ID numbering.
BUG_BOUNTY_SCENE
constantThe strings of the hero's triage terminal.
BUG_BOUNTY_FAQ
constantSix researcher questions.
DEFAULT_BUG_BOUNTY_PAGE_LABELS
constantThe English strings.
BUG_BOUNTY_PAGE_DESIGNS
constantThe design names, classic first: ["classic", "terminal", "minimal"].
BugBountyPageProps
typeProps of BugBountyPage.
BugBountyPageDesign
type"classic" | "terminal" | "minimal".
BugBountyPageLabels
typeThe strings labels can override.
BugBountyReportValues
type{ title, asset, vulnerabilityType, severity, steps, impact, files, email, agree } passed to onSubmitReport.
BugBountyCvssInput
typeThe five inputs of cvssScore.
BugBountyReward
typeOne row of the rewards table.
BugBountyAsset
typeOne in-scope asset.
BugBountyResearcher
typeOne leaderboard entry.
BugBountyDisclosedReport
typeOne disclosed report.
Examples
Terminal design
design="terminal": a dark monospace page in both themes, $-prefixed eyebrows, a green dotted backdrop, hairline panels and dashed rules.
Minimal design
design="minimal": a transparent header, a centered hero without the terminal, outlined panels, no bands and a plain closing band.
Brand orange, centered hero
heroLayout centered with tone and ctaTone brand; the scope opens on the out of scope tab and the board on 2025.
Disclosure policy only
A vulnerability disclosure program without bounties: scope, rules, timeline, the form and the FAQ, in en-GB.
When the submit fails
onSubmitReport rejects: after the spinner the form keeps everything and shows the error above the button.
Dependencies
Files
- components/templates/bug-bounty-page.tsx
- components/templates/bug-bounty-page-data.ts