11.5 Information Disclosure: Error Messages & Mark-up Leakage

Key Takeaways

  • Verbose error messages disclose software versions, file-system paths, SQL fragments, stack traces and internal hostnames that map the application's internals.
  • The HTTP status code and the error body must both be reviewed: a 500 with a stack trace is far more useful than the code alone.
  • HTML source routinely leaks hidden form fields, developer comments, connection strings, credentials, API keys and links to authenticated-only URLs.
  • Client-side JavaScript and its source maps expose endpoints, feature flags and logic not visible in the rendered page.
  • Remediation is generic error pages, server-side logging of detail, and removing sensitive content from client-delivered mark-up and scripts.
Last updated: September 2026

11.5 Information Disclosure: Error Messages & Mark-up Leakage

Two syllabus items combine into a single discipline: reading what the application tells you that it did not mean to. H8 (Information Disclosure in Error Messages) covers how error messages indicate or disclose useful information. H3 (Information Gathering from Web Mark-up) covers the intelligence in web page source — hidden form fields, database connection strings, credentials, developer comments, other included files, and authenticated-only URLs.

Neither is a dramatic exploit on its own. Both are force multipliers: they turn a black-box target into a partially white-box one, telling you the software, the versions, the file paths, the hidden parameters and often the credentials that make every subsequent attack faster and more reliable.


1. Information Disclosure Through Error Messages (H8)

When an application encounters an unexpected condition, a poorly configured one tells the user what went wrong in technical detail. That detail is written for a developer debugging locally, not for an anonymous internet user, and it leaks accordingly.

What Errors Disclose

Error contentIntelligence it hands the attacker
Stack traceFramework and exact version, class and method names, file-system paths, line numbers
SQL errorThe DBMS and version, table/column names, and often the injected query itself — the engine of error-based SQLi (12.2)
Path in an errorThe web root and directory layout, enabling path traversal and LFI (11.1)
"File not found: /var/www/app/inc/db.php"Absolute paths, include structure, technology (.php)
Internal hostname / IP in an errorBack-end topology (database server names, internal addresses)
Differing error for valid vs invalid usernameUsername enumeration (H4)
Version banners in default error pagesThe Apache/IIS/nginx and app-server versions to match against advisories

Status Codes and Bodies Together

Review both the HTTP status code (section 10.1) and the response body. A bare 500 Internal Server Error is uninformative; a 500 whose body contains a full framework stack trace is a map of the application. Equally, differences in behaviour matter more than any single response: an application that returns 404 for a non-existent file but 403 for one that exists-but-is-forbidden has just disclosed which files exist. Deliberately provoke errors to harvest this:

  • submit unexpected types (a string where a number is expected, an array where a scalar is expected);
  • send malformed input (broken JSON/XML, an oversized value, a null byte);
  • request non-existent and forbidden resources;
  • interrupt multi-step flows out of order.

The Debug-Mode Trap

The single richest source is an application left in debug/development mode in production — Django's debug page, ASP.NET's "yellow screen of death" with customErrors="Off", Rails' exception page, PHP with display_errors=On. These render the full stack, local variables, configuration and sometimes environment variables (including secrets) directly to the browser. Finding one is a high-severity finding on its own.


2. Information Gathering from Web Mark-up (H3)

The rendered page is only part of what the server sends. The source — HTML, comments, inline scripts, linked files — carries far more, and it costs nothing to read (Ctrl+U, curl, or Burp's response view).

Hidden Form Fields

<input type="hidden"> values are invisible in the browser but fully present in the source and fully editable by the client. They routinely carry prices, user IDs, roles, quantities, discount flags and state that the developer assumed the user could not change — the foundation of parameter tampering (11.1). A hidden <input name="price" value="9.99"> or <input name="isAdmin" value="false"> is a classic finding.

Developer Comments

HTML and JavaScript comments are delivered to the client verbatim. They disclose:

  • work-in-progress notes ("TODO: remove test admin account before go-live");
  • disabled or commented-out functionality and its URLs;
  • credentials and connection strings pasted "temporarily";
  • internal ticket numbers, developer names and email addresses;
  • explanations of how a control works, which explains how to defeat it.

Connection Strings, Credentials and Keys

Secrets end up in client-delivered content more often than anyone expects: a database connection string in an HTML comment or an inline script, a third-party API key hardcoded in JavaScript, AWS keys in a bundled config, Basic-auth credentials embedded in a URL. Search the source and every linked script for password, passwd, secret, apikey, api_key, connectionString, AKIA (AWS), and private-key headers.

Other Included Files and Authenticated-Only URLs

  • Linked resources<script src>, <link href>, source-map (//# sourceMappingURL) references, and paths in JavaScript reveal the file structure and additional endpoints.
  • Authenticated-only URLs — the mark-up frequently references admin panels, API endpoints or privileged functions that are hidden from the UI by CSS or conditional rendering but present in the source. These feed forced browsing (10.3) and access-control testing: a link to /admin/users present in the page of a non-admin user is a lead to a broken-access-control finding.

Client-Side JavaScript

Modern single-page applications ship much of the application's structure in JavaScript. Reading the bundles (beautified, and via source maps where present) reveals every API endpoint the front-end knows about, feature flags, role names, and validation logic — a comprehensive endpoint list for testing, often including routes never linked in the visible UI. Tools like LinkFinder and Burp extract URLs and parameters from JS automatically.


3. A Systematic Review

 For every response the application returns:
   1. Read the status code AND the body
   2. View source: HTML comments, hidden fields, inline scripts
   3. Fetch and beautify every linked JS/CSS file; follow source maps
   4. Grep source + scripts for: password secret apikey connectionString
                                  AKIA BEGIN PRIVATE KEY /admin /api TODO
   5. Provoke errors deliberately; capture verbose output and paths
   6. Compare responses (valid vs invalid, exists vs forbidden)
   7. Feed discovered endpoints/params back into content discovery + access tests

4. Remediation

The fixes are well understood and worth stating precisely in a report:

  • Generic error pages for all unhandled exceptions; log the technical detail server-side where only administrators see it. Disable debug mode in production (customErrors="On", display_errors=Off, DEBUG=False).
  • Consistent responses where disclosure would aid enumeration — identical messages and timing for valid and invalid usernames, identical handling for existing-but-forbidden and non-existent resources.
  • Do not put secrets in client-delivered content — no credentials, connection strings or API keys in HTML, comments or JavaScript; keep secrets server-side and inject third-party keys through a back-end proxy where possible.
  • Strip comments and source maps from production builds, and remove hidden fields that carry security-relevant state — move that state server-side (session) and never trust a client-supplied price or role.
  • Suppress version banners in server and framework headers and default pages.

The through-line is the same as the rest of the web chapters: the client sees everything the server sends, so nothing sensitive should be sent, and nothing the client can alter should be trusted.

Test Your Knowledge

During testing, submitting a single quote in a search box returns HTTP 500 with a body containing 'ORA-00933: SQL command not properly ended' and a file path /u01/app/oracle/product/. What has the application disclosed?

A
B
C
D
Test Your Knowledge

An assessor views the HTML source of a checkout page as a normal user and finds <input type="hidden" name="price" value="149.99"> and an HTML comment reading '<!-- TODO: remove connStr Server=db01;Uid=sa;Pwd=Summer2026 -->'. Which statement is correct?

A
B
C
D
Test Your Knowledge

Why should an assessor retrieve and beautify a single-page application's JavaScript bundles rather than testing only the links visible in the rendered UI?

A
B
C
D
Test Your Knowledge

What is the correct remediation for an ASP.NET application that displays a full stack trace with local variables when an unhandled exception occurs in production?

A
B
C
D