Step 314. Starting Bug Bounty — Understanding the System and Picking Your First Target

Step 314. Starting Bug Bounty — Understanding the System and Picking Your First Target

Level 4 — Bug Bounty | Difficulty ★★☆☆☆ | Estimated time: 2 hours

Prerequisites: you have finished Step 171 (OSINT advanced) attack-surface concepts and the Level 2–3 web vulnerability basics. You can read basic Python syntax.

  • What you need: Python 3, a notepad (for the operations brief). Signing up for a real platform is optional, and every platform screen in this chapter is an example.
  • ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime.
  • Caution: bug bounty is legal only inside the scope and rules the program states. Even a single out-of-scope request can be illegal. This boundary is the premise of this entire Level.

Every attack technique you’ve learned so far could only be used inside a lab. Starting today, that’s different — there are companies in the world that publicly declare, "Attack our service, and if you find something, we’ll pay you." This is bug bounty. But it is not freedom; it is a contract. Today you learn not attack technique, but how to read that contract.


1. Learning Objectives

By the end of this chapter, you will be able to:

  • Explain the structure of the bug bounty system (platforms, programs, triage)
  • Find and read the scope, prohibited actions, and reward table on a program policy page
  • Judge what a wildcard scope like *.example.com includes and excludes
  • State the difference between valid, duplicate, informative, and N/A verdicts
  • Apply the first-target selection criteria to write one "operations brief"

2. Background Knowledge — Today’s Tools and Concepts

Today’s Tools at a Glance

Category Details
Language/environment Python 3 (scope-judgment principle practice)
Today’s tools (concept intro) HackerOne · Bugcrowd · KISA vulnerability reward program (KVE), (hands-on) scope-judgment script
Concepts needed Scope, wildcards, reward tiers, verdict types, competition density
Today’s deliverable 1 target program + 1 operations brief

2-1. What Is Bug Bounty — A Contract with an Attack Permit Attached

A bug bounty is a program in which a company pays rewards for vulnerability reports against its own services. The core is this — it is the only zone in this entire book where offensive action against a real service becomes legal.

However, conditions apply. It is permitted only inside the scope (target domains, IPs, apps) and rules each program states. The scope is the permit’s valid area. A request to an out-of-scope system is just plain illegal intrusion, even mid-participation in a bug bounty.

2-2. The Platform Structure — Who Sits in the Middle

There are three representative channels. HackerOne and Bugcrowd are international platforms where countless companies’ programs gather. In Korea there is the KISA Software New Vulnerability Reward Program (KVE).

On a platform, the person you deal with is the triager (the report reviewer). When a report comes in, the triager reproduces it and issues a verdict. That flow — submit, review, verdict, reward — is bug bounty’s basic loop.

2-3. Scope and Rules — The Body of the Contract

A program policy page states four things. ① In-scope: the list of assets you may test. ② Out-of-scope: assets you must not touch. ③ Prohibited actions: behavioral rules like no denial-of-service testing, no social engineering, automated-scan rate limits. ④ Reward table: the amounts per severity tier.

Wildcard interpretation is what beginners get wrong most. If *.example.com is in scope, are all subdomains fair game? Is the root domain (example.com) itself included? Mobile apps? Third-party services (payment processors, etc.)? The correct answer differs per program, so only the sentences written on the policy page are the answer.

2-4. Verdict Types — Most Reports Aren’t Rewards

Submit a report and the answer that comes back is mostly one of four.

Verdict Meaning Reward
Valid / resolved Recognized as a real vulnerability Yes
Duplicate Someone reported it first No
Informative True, but weak security impact No
Not applicable (N/A) Cannot be considered a vulnerability No

One sobering fact — most reports end as duplicate, informative, or N/A. Taking time to reach your first valid verdict is normal, which is why the first goal must be not "a big payout" but "the experience of 1 valid verdict."

2-5. First-Target Selection Criteria — Go Where Competition Is Low

Famous programs like Google and Apple are swept daily by the world’s best hunters. A beginner’s odds of a first valid report there are low. The conditions of a beginner-friendly program are these.

  • Wide scope — open as a wildcard (*.domain), so there are many assets to explore
  • Low competition — a new program, or few participants (few resolved reports)
  • A clear reward table — per-tier amounts written down, so you can set expectations
  • Fast response — the average triage response time is published and short

3. Follow Along

3-1. Dissecting a Program Policy Page — Screen Example

Learn the typical shape of a policy page through a screen example. Sign up for a platform and open a real page, and it has exactly this structure.

Screen example (the shape of a HackerOne program policy page — a fictional program):

  Example Corp Security Program
  ┌──────────────────────────────────────────────┐
  │ Scope (targets)                              │
  │   In scope:  *.example-corp.com              │
  │              Example iOS/Android apps        │
  │   Out of scope: status.example-corp.com      │
  │                 all third-party services     │
  │                                              │
  │ Rules (prohibited actions)                   │
  │   - No DoS/DDoS testing                      │
  │   - No social engineering / phishing         │
  │   - Automated scans limited to 5 req/sec     │
  │   - No access to others' accounts or data    │
  │                                              │
  │ Rewards                                      │
  │   Critical $5,000 / High $1,500              │
  │   Medium $500   / Low $100                   │
  └──────────────────────────────────────────────┘

How to read it: look at the four boxes in order — targets, exclusions, prohibited actions, rewards. This page is the contract, and "I didn’t know" doesn’t work. The example’s program, domains, and amounts are all fabricated data.

3-2. Scope-Reading Practice — Four Questions

Look at the screen example’s scope and answer these four yourself.

Question The answer in this example
Is api.dev.example-corp.com in scope? Yes — caught by *.example-corp.com
Is the root example-corp.com in scope? Unclear — if not stated in the policy, ask or treat as excluded
status.example-corp.com? No — explicitly excluded
The payment processor’s pages? No — third-party services excluded

How to read it: the core instinct is "if it isn’t stated, it isn’t in scope." The moment you test an ambiguous asset you may step out of the legal zone, so when it’s ambiguous, don’t — or ask the program first.

3-3. The Wildcard-Judgment Principle — Measured

Let’s judge "is it caught by *.lab.local?" in code. Watch how a machine interprets the policy sentence, and scope-reading becomes instinct.

Input: scope_check.py:

import re

scope_in  = ["*.lab.local"]                                # in scope
scope_out = ["status.lab.local", "thirdparty.example.com"] # explicit exclusions

def in_scope(host):
    for pat in scope_out:                                  # exclusions always first
        if re.fullmatch(pat.replace("*.", r"(.+)."), host):
            return False, f"matches exclusion ({pat})"
    for pat in scope_in:
        if re.fullmatch(pat.replace("*.", r"(.+)."), host):  # strict: subdomain required
            return True, f"matches scope pattern ({pat})"
    return False, "no scope pattern match"

tests = ["www.lab.local", "lab.local", "dev.api.lab.local",
         "status.lab.local", "lab.local.evil.com", "thirdparty.example.com"]
for h in tests:
    ok, why = in_scope(h)
    print(f"{h:28s} -> {'IN ' if ok else 'OUT'} ({why})")

Output (measured 2026-09-09):

www.lab.local                -> IN  (matches scope pattern (*.lab.local))
lab.local                    -> OUT (no scope pattern match)
dev.api.lab.local            -> IN  (matches scope pattern (*.lab.local))
status.lab.local             -> OUT (matches exclusion (status.lab.local))
lab.local.evil.com           -> OUT (no scope pattern match)
thirdparty.example.com       -> OUT (matches exclusion (thirdparty.example.com))

How to read it: three things to see. ① Deep subdomains like dev.api.lab.local are also caught by the wildcard. ② lab.local.evil.com is a different domain despite the similar look — OUT. ③ And most important — the root domain lab.local came out OUT. That’s because this judge interpreted *. strictly as "a subdomain must be present."

Why do this: real programs are split on this interpretation too. Some programs include the root domain and some don’t. So when the policy doesn’t state it, not touching the root domain is the safe default. Judge it yourself in code, and this ambiguity gets into your hands.

3-4. Reading the Reward Tier Table — Screen Example

Reward tables usually have four severity tiers. This is a screen example.

Screen example (a fictional program's reward table):
  Critical — remote code execution, unauthenticated full DB access   $5,000
  High     — account takeover of others, stored XSS (targeting admin) $1,500
  Medium   — IDOR (reading others' data), privilege escalation        $500
  Low      — reflected XSS, information disclosure (limited)          $100

How to read it: read the tier criteria sentences, not the reward amounts. Only when there’s a criterion like "reading others’ data = Medium" do you later have grounds to argue which tier your finding belongs to. Remember that even the same IDOR lands in different tiers depending on what data is exposed.

3-5. Writing the Operations Brief

Once you’ve picked your first target (or use the fictional practice program), make a one-page operations brief. This document is the boundary line for everything you do from here on.

# Operations Brief — (program name) / Date: ____

### Scope (never step outside it)
- IN:  *.example-corp.com, mobile apps
- OUT: status.example-corp.com, all third-party services

### Prohibited actions
- No DoS / automated scans max 5 req/sec / no access to others' data

### Reward criteria (my target tier: Medium)
- Medium $500 — reading others' data, e.g., IDOR

### Reason for selection
- New program (few resolved reports), wide assets via wildcard scope

### My test accounts
- Account A: ____ / Account B: ____ (testing happens only between these two accounts)

How to read it: the "my test accounts" box matters. Bug bounty verification happens, as a rule, only between accounts you created yourself. Anything outside this brief is not "study" — it’s intrusion.


4. Missions & Exercises

Mission — Complete One Operations Brief

  1. Read the policy pages of 3 programs on a real platform (HackerOne, etc.), or use the fictional program from 3-1 as your target
  2. Build a table comparing the candidates on 2-5’s four selection criteria (scope width, competition, reward table, response speed)
  3. Complete an operations brief in the 3-5 format — including scope, prohibited actions, reward criteria, and reason for selection
  4. Add 3 hosts to 3-3’s scope_check.py, run the judgment, and attach the result to the brief
  5. Write "I will never step outside this document’s scope" on the brief’s last line, with the date

Exercises

Exercise 1. Explain from the "contract" perspective why attacks in bug bounty are legal, and why an out-of-scope request is illegal even while participating in a bug bounty.

Exercise 2. Using 3-3’s measured result as grounds, explain why the handling of the root domain example.com differs per program when *.example.com is in scope.

Exercise 3. Explain why a duplicate verdict is "common," not "a lack of skill," citing the structure of bug bounty.

Exercise 4. Give two reasons why "a program with wide scope and low competition" favors beginners.


5. Model Answers & Completion Criteria

Mission Model Answer

Example of the candidate-comparison table (program names fabricated):

Criterion Program A (famous) Program B (new)
Scope Limited to 3 domains *.domain wildcard
Resolved reports 4,000+ (fierce competition) 30 (low competition)
Reward table Clear Clear
First-target fit Low High — selected

How to verify: ① are the 4 comparison criteria in the table? ② is the IN/OUT scope transcribed into the brief word for word? ③ is the scope_check.py run result attached? ④ is the "never step outside" declaration present? All ‘yes’ means complete.

Exercise Answers

Answer 1. A bug bounty is a contract in which a company publicly promises "for this range (scope), under these rules, we permit testing," and the participant has accepted those conditions. The permission exists only inside the boundary called scope, so a request to an out-of-scope system is legally identical to an ordinary unauthorized intrusion. It is not the status of "bug bounty participant" that is protected — only "actions inside the permitted range."

Answer 2. In 3-3’s measurement, lab.local was judged OUT — because *. was interpreted strictly as "subdomain required." But that interpretation may differ from the program author’s intent. Some programs meant to include the root in *.example.com, and some actually list example.com separately. Because the mechanical interpretation diverges, when the policy doesn’t state it, you must leave the root domain alone or ask.

Answer 3. In a popular program, hundreds of hunters are looking at the same features at the same time. There is one vulnerability and several reports, so only the earliest report becomes valid and all the rest become duplicates. It’s a matter of timing, regardless of skill. So a duplicate verdict is accurately read as "had the skill to find it, but was late," and choosing a low-competition program is the strategy that lowers the duplicate rate.

Answer 4. First, a wide scope means many assets (subdomains, features) to explore, so there’s a higher probability that corners nobody has looked at yet remain. Second, low competition means a lower probability that someone submits first between your discovery and your report, so you get fewer duplicate verdicts. If the first goal is "the experience of a valid verdict," these two conditions raise the success probability the most.

Completion Criteria Checklist

  • [ ] I can explain that bug bounty is "a contract that is legal only inside scope"
  • [ ] I can find and read the policy page’s 4 elements (targets · exclusions · prohibitions · rewards)
  • [ ] I verified the root-domain ambiguity of wildcard scopes hands-on
  • [ ] I can distinguish and state the 4 verdict types (valid · duplicate · informative · N/A)
  • [ ] I applied the 4 first-target selection criteria to compare candidates
  • [ ] I completed one operations brief

6. Common Pitfalls & Fixes

Wall 1. Coveting the famous programs first

Symptom: you start by looking at the Google, Apple, Facebook programs.
Cause: choosing by reward amount.
Fix: the first goal is not money but the experience of 1 valid verdict. Famous programs are swept daily by the world’s best, so few vulnerabilities remain and the duplicate rate is high. Start with a new, wide-scope program per 2-5’s criteria.

Wall 2. Skimming the scope and starting

Symptom: thinking "it’s a wildcard, everything’s fair game," you test and touch an excluded asset.
Cause: not reading the policy page closely.
Fix: make 3-5’s operations brief before testing. The rule is: don’t touch assets not in the brief. Squatting domains that merely look similar, like lab.local.evil.com, are never in scope (3-3 measurement).

Wall 3. The judge’s result differs from my expectation

Symptom: you’re flustered that lab.local came out OUT in scope_check.py.

lab.local                    -> OUT (no scope pattern match)

Cause: not a bug but an intended strict interpretation — *. was implemented as "a subdomain must be present" (measured 2026-09-09).
Fix: this ambiguity itself is today’s lesson. In real policies too, when not stated, holding off on the root domain and asking the program is the safe default.

Wall 4. Getting discouraged by a duplicate verdict

Symptom: your first report comes back duplicate and you lose motivation.
Cause: reading duplicate as a signal of "no skill."
Fix: duplicate means "found it, but late" — and it’s evidence of skill. Structurally, most reports in popular programs end as duplicates (Exercise 3). Moving to a lower-competition program is the correct answer that raises the odds.


7. Summary

Today’s Concepts

Concept One-line explanation
Bug bounty A system that rewards vulnerability reports — a contract legal only inside scope
Scope The testing-permit zone — the IN/OUT list and prohibited actions are the contract’s body
Triager The reviewer who reproduces reports and issues verdicts
4 verdict types Valid (reward) · duplicate · informative · not applicable (no reward)
Wildcard *.domain All subdomains — whether the root domain is included varies per program
Operations brief The boundary document of my activity — a summary of scope, rules, test accounts
First-target criteria Wide scope · low competition · clear reward table · fast response

Today’s Commands & Code

Tool What it does
re.fullmatch(pattern, host) Judge whether a host exactly matches a scope pattern
pattern.replace("*.", r"(.+).") Convert a wildcard to a regex (subdomain-required interpretation)
Check the exclusion list first OUT beats IN — an explicit exclusion always wins

The Core Instinct

What you learned today is not technique but boundaries. Bug bounty is not "a world where you may attack" but "a game where you read the permit and move only inside it." The habit of reading the policy page closely, the default of not touching what’s ambiguous, the attitude of reading duplicates as statistics rather than failure — these three are the roots of all of Level 4. Once the operations brief is complete, from here on you actually draw the map and find vulnerabilities inside that boundary.


Once every box is checked, Step 314 is complete.