Information disclosure is easy to underestimate because the first response often looks passive: a version string, a debug page, a source backup, a header name, a Git diff.

The useful question is not “is this secret-looking?” It is “what missing exploit parameter did this just supply?”

Leaks complete chains

The five PortSwigger labs cover five common surfaces:

  • verbose error messages reveal framework versions;
  • debug pages reveal environment variables;
  • backup directories reveal source code and hard-coded passwords;
  • TRACE reveals front-end-added internal headers;
  • exposed Git metadata reveals old secrets in history.

The series was re-run and live-verified on 2026-05-30 as 5/5 solved.

None of these require exotic tooling. They reward a disciplined first pass.

Trigger errors on purpose

If an endpoint expects an integer, send a string:

GET /product?productId="example"

A production app should return a generic error. A vulnerable one may return a stack trace with framework names, versions, file paths, and class names. In the lab, that is enough to identify the exact Apache Struts version.

Debug pages are secret aggregators

An HTML comment points to:

/cgi-bin/phpinfo.php

That page exposes SECRET_KEY. In real assessments, the same pattern often leaks database DSNs, cloud credentials, internal paths, feature flags, or signing keys. A debug page is a secret aggregator, not a harmless diagnostics screen.

Robots is not access control

/robots.txt reveals /backup, which exposes ProductTemplate.java.bak. The source contains a database password.

The durable rule is that crawl hints are public. If a path must not be read, it needs authentication or must not be deployed.

TRACE can reveal trust boundaries

The auth-bypass lab depends on a custom header added by the front-end:

X-Custom-IP-Authorization: <client-ip>

TRACE /admin reflects the request and reveals the header name. Once known, sending:

X-Custom-IP-Authorization: 127.0.0.1

bypasses the local-origin gate.

The deeper issue is that the origin trusts a header the client can eventually learn and forge.

Git history remembers removed secrets

Exposed /.git/ data lets the attacker inspect commit history. A commit named “Remove admin password from config” is effectively a treasure map. The current file may use an environment variable, but the old hard-coded password remains visible in the diff.

Deleting a secret from the latest commit is not enough. Once public, rotate it.

Defender notes

Hardening:

  • return generic production errors;
  • disable public debug pages and phpinfo;
  • prevent directory indexes and source backups from being deployed;
  • treat robots and sitemaps as public data;
  • disable TRACE unless deliberately needed;
  • strip internal trust headers at the edge;
  • keep .git, .svn, and .hg out of the webroot;
  • rotate secrets that appeared in public responses or repository history.

Detection:

  • malformed parameter probes that trigger 500 responses;
  • requests for /backup, *.bak, *.old, *~, and /cgi-bin/phpinfo.php;
  • TRACE requests;
  • .git/HEAD, .git/config, and .git/objects/ access;
  • external clients supplying internal-only headers.

Leaks matter because they remove uncertainty. Treat every accidental detail as a possible parameter in the next request.