Skip to content

API Security & Bug Bounty

Bug bounty is authorized security testing: a company publishes a program that gives you legal permission to probe defined assets, and pays you for valid, well-reported vulnerabilities. This section teaches API bug hunting from the terminal — curl, jq, ffuf, nuclei, and friends — because the command line is the fastest, most precise, most repeatable way to talk to an HTTP API.

Everything here assumes you are testing assets you are explicitly permitted to test. Read the next section before you read anything else.

Authorization, scope, and legality come first

Section titled “Authorization, scope, and legality come first”

There is exactly one thing that separates a bug bounty hunter from a criminal: authorization. The same curl command is legitimate research against an in-scope target and a computer-crime offense against one you have no permission to touch. The techniques are identical; the authorization is everything.

The rules that keep you safe and welcome:

  • Only test in-scope assets. A program’s policy lists exactly which domains, apps, API endpoints, and IP ranges are fair game — and, just as importantly, which are out of scope. If it is not listed as in scope, treat it as forbidden.
  • Never touch third-party or out-of-scope systems. A target often integrates payment processors, CDNs, analytics, cloud providers, and other vendors. Those belong to someone else and are almost always out of scope. Pivoting into them is not “part of the finding” — it is a separate intrusion.
  • Respect the rules of engagement. Programs specify what you may do: whether automated scanning is allowed, what rate limits to honor, whether social engineering / physical / DoS testing is banned (it almost always is), whether you must use a specific test account or a tagged user-agent.
  • Respect rate limits. Hammering an API is how you cause an outage, get your IP banned, and get removed from a program. Throttle. Most tools have a rate flag — use it.
  • Do no harm. No destructive actions. Prove a bug with the minimum interaction needed. Don’t exfiltrate real user data, don’t pivot, don’t persist. If you can demonstrate access with one record or a redacted screenshot, stop there.
  • Disclose responsibly. Report privately through the program, give the vendor time to fix, and don’t publish details until they permit it (coordinated disclosure).
  • Practice on assets you own. Before you touch a real program, sharpen these tools on your own infrastructure — for Shopify, a development store and a test app you created yourself (more below), or dedicated legal labs.

Most public programs — including Shopify’s — run on a coordinated-disclosure platform. HackerOne is the most common; Bugcrowd, Intigriti, and YesWeHack work similarly. The moving parts:

  • Program — a company’s page with its policy, scope, and reward table. Read the policy top to bottom before testing.
  • Scope — the explicit list of assets. Usually split into in-scope (test these) and out-of-scope (do not). Assets carry an asset type (URL, wildcard domain, mobile app, source code, etc.).
  • Rules of engagement — permitted and forbidden activities, required test accounts, disclosure timeline, safe-harbor language.
  • Report — your write-up of a single vulnerability: what it is, where, reproduction steps, impact, and a suggested fix. One bug per report.
  • Triage — a human (platform staff or the vendor) validates and reproduces your report, assigns a state, and may ask for more detail. Common states: New → Triaged → Resolved, or Duplicate / Informative / N/A (not applicable).
  • Duplicate — someone reported the same bug first. First valid report usually wins the bounty; this is why speed and clarity matter, but never at the cost of scope discipline.
  • Severity / CVSS — impact is scored, commonly with CVSS (Common Vulnerability Scoring System) producing a 0.0–10.0 number and a Low/Medium/High/Critical band. HackerOne also has a simpler severity picker. The score drives the bounty.
  • Bounty — the reward, if the report is valid, in scope, and not a duplicate. Reputation and signal metrics also accrue on the platform.

A strong report is worth more than a clever bug. It states the vulnerability class, gives copy-paste reproduction (often the exact curl command), shows concrete impact, and stays strictly within scope.

Bounties scale with impact, and impact is usually scored with CVSS — a formula that turns a bug’s properties into a 0.0–10.0 number and a band:

Band CVSS range Rough meaning
Critical 9.0–10.0 Full compromise, mass data exposure
High 7.0–8.9 Serious impact on confidentiality/integrity
Medium 4.0–6.9 Meaningful but constrained impact
Low 0.1–3.9 Minor, hard to exploit, or low value

CVSS inputs include the attack vector (network vs local), privileges required, user interaction, and the impact to confidentiality, integrity, and availability. You don’t need to compute it by hand — the platform provides a picker — but understanding it helps you argue impact honestly. An IDOR that exposes other users’ orders (confidentiality, no privileges, network) scores far higher than a self-only issue. State the realistic impact; don’t inflate it.

Bug hunting is a loop, not a single scan. The terminal supports every stage:

  1. Recon — map the organization’s footprint: subdomains, live hosts, technologies, historical URLs, exposed JS. Covered in Recon & enumeration.
  2. Map — for each in-scope host, enumerate endpoints, parameters, auth mechanisms, and content types. Build a picture of the API surface.
  3. Test — probe each endpoint for a specific bug class: broken authorization (IDOR/BOLA), mass assignment, injection, logic flaws, information disclosure. See Testing REST APIs and Testing GraphQL APIs.
  4. Verify — reproduce the finding cleanly, minimize the request, confirm it isn’t a fluke or a duplicate, and capture exact evidence.
  5. Report — write it up clearly, privately, with reproduction and impact, and disclose responsibly.

Recon feeds mapping, mapping feeds testing, and a verified finding loops you back to look for variants nearby.

Everything in this section is command-line first. The core kit:

Tool Role Page
curl Craft any HTTP request precisely HTTP recon toolkit
HTTPie Friendlier HTTP client for quick pokes HTTP recon toolkit
jq Slice and filter JSON responses HTTP recon toolkit
ffuf Fast fuzzer for endpoints, params, values Testing REST APIs
subfinder / amass / assetfinder Subdomain enumeration Recon & enumeration
dnsx / httpx Resolve and probe live hosts Recon & enumeration
gau / waybackurls Historical URLs from archives Recon & enumeration
nuclei Templated vulnerability scanning Recon & enumeration
graphw00f / clairvoyance Fingerprint and map GraphQL APIs Testing GraphQL APIs

Most of these are Go binaries you install once and run anywhere. A quick install of the ProjectDiscovery core:

Terminal window
# Requires a recent Go toolchain (go 1.21+)
go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install -v github.com/projectdiscovery/dnsx/cmd/dnsx@latest
go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# ffuf and the archive tools
go install github.com/ffuf/ffuf/v2@latest
go install github.com/lc/gau/v2/cmd/gau@latest
go install github.com/tomnomnom/waybackurls@latest
# jq and HTTPie usually come from your package manager
sudo apt install jq httpie # Debian/Ubuntu
# brew install jq httpie # macOS

Isolate your testing so mistakes stay contained and evidence stays clean:

  • A dedicated machine or VM, and a browser profile used only for bug hunting. Keep your personal cookies and sessions out of it.
  • An intercepting proxy (Burp Suite or OWASP ZAP) so every request is logged and replayable. Point your tools at it with -x http://127.0.0.1:8080 (curl) so nothing you send is lost.
  • Test accounts only. Create the program’s required accounts. Never test with a real user’s session, and never use production data as your payload.
  • Note-taking from the start. One directory per target, timestamped output files, and a running log of what you tried and what happened. You cannot write a good report from memory.
Terminal window
# A simple per-target workspace
mkdir -p ~/bounty/example-corp/{recon,http,notes}
cd ~/bounty/example-corp
date -u > notes/session-$(date +%F).log # timestamp every session

API programs pay most for authorization and logic bugs, because they can’t be caught by a signature and they map directly to real-world harm. A tester’s-eye view of what to look for and where each is covered:

Class What it is Where
IDOR / BOLA Accessing objects that aren’t yours by changing an ID Testing REST APIs, GraphQL
Broken authentication Missing/weak enforcement of who you are Testing REST APIs
Mass assignment Setting fields the UI never exposes (role, verified) Testing REST APIs
Parameter tampering / logic Trusting values you control (price, quantity, status) Testing REST APIs
Information disclosure Verbose errors, exposed schemas, leaked keys in JS Recon & enumeration
Missing rate limits Sensitive actions with no throttle (report, don’t abuse) Testing REST APIs, GraphQL

Start with authorization — it’s the highest-value, most abundant class, and the easiest to prove safely using two of your own test accounts.

A finding is only worth what your report can prove. A strong one is short and unambiguous:

  • Title — the bug class and the affected asset in one line: “IDOR in GET /orders/{id} exposes other merchants’ orders.”
  • Summary — one paragraph: what the bug is and why it matters.
  • Steps to reproduce — numbered, with the exact curl commands and the two test accounts used. The triager should reproduce it by pasting your commands.
  • Impact — the realistic consequence, mapped to CVSS. Honest, not inflated.
  • Evidence — trimmed request/response pairs (redact real data), and a note that you accessed only your own second account’s record.
  • Remediation — a concrete fix (“enforce object-level authorization: check the order’s owner_id against the session user”).
report-skeleton.md
## Summary
<one paragraph>
## Steps to reproduce
1. As account A (yours), create order 1001.
2. As account B (yours), run:
curl -sS https://api.example.com/orders/1001 -H "Authorization: Bearer <B>"
3. Observe account A's order returned to account B.
## Impact
Any authenticated user can read any other user's orders (CVSS ~7.5, High).
## Remediation
Enforce object-level authorization on /orders/{id}.

Shopify runs a mature, long-standing public program on HackerOne with clearly defined scope and rules. A few things to keep in mind — but always defer to their current, published policy, which supersedes anything here:

  • Read the live policy and scope every time. Mature programs are precise about what is in and out of scope, and they update it. Assume nothing.
  • Practice on your own assets. Shopify makes this easy and legitimate:
    • A Partner account lets you create free development stores — full stores you own and control, ideal for learning the storefront and Admin APIs safely.
    • You can build a custom or public app against your own dev store and test it with your own API tokens.
    • Shopify’s Admin API is GraphQL (with a legacy REST Admin API), so the GraphQL testing page is directly relevant — practiced against your own store and your own tokens.
  • Third-party apps and other merchants’ stores are not yours. A store you did not create, or an app you do not own, is someone else’s property and out of bounds unless the policy explicitly says otherwise.
  • Authorization is the whole game. Test only what a program’s published scope permits; everything out of scope is off-limits.
  • HackerOne coordinates programs, scope, reports, triage, and bounties; duplicates go to whoever reported first — but never rush past scope to be fast.
  • The workflow is a loop: recon → map → test → verify → report, all driven from the terminal.
  • Learn the core kit (curl, jq, ffuf, the ProjectDiscovery tools) and always run through a logging proxy with clean test accounts.
  • For Shopify, practice on your own development stores and apps; its Admin API is GraphQL. Re-read the current policy before every session.