Vulnerabilities
ELMAH vs trace.axd on Production ASP.NET Sites
August 11, 2023
ELMAH vs trace.axd on production ASP.NET sites is two leftover operator UIs. ELMAH's /elmah.axd (and similar handlers) is an error log viewer: exception text, URLs, sometimes cookies or form fields depending on what was logged. ASP.NET tracing's /trace.axd is a request trace viewer enabled when tracing is on in web.config. Neither is a login by itself; both shrink reconnaissance and can donate secrets that ended up in an exception. Production belongs on server-side logs behind the firewall, not a public .axd. RoastMyOpsec does not currently score /elmah.axd or /trace.axd. It does not enable tracing, does not dump ELMAH stores, and does not treat a 404 as proof the handler is gone.
The practical difference
trace.axd is the framework's built-in request log when tracing is enabled. ELMAH is a package that captures unhandled exceptions into a store and, historically, a browser UI. phpinfo() is the PHP cousin. Spring Actuator is the Java cousin. Framework DEBUG is every 500 without a dedicated page. Lock each layer.
robots.txt Disallow: /elmah.axd advertises the name. Deny at the CDN instead. A downloadable web.config that still has tracing enabled is a second leak — see .htaccess vs web.config.
How to choose what to expose
Public origin: no ELMAH UI, tracing off, customErrors On or RemoteOnly with generic pages. Logs: file, SQL, or a SIEM you authenticate to — not an .axd on 443. Staging: same deny list if the hostname is guessable. CDN: deny /elmah.axd, /trace.axd, and common handler names even if 'IIS is internal.'
| Surface | Typical leak | Public origin | Takeaway |
|---|---|---|---|
| /elmah.axd | Exception log, often request data | No | Not a scored roast path; deny anyway |
| /trace.axd | Recent request traces | No | Turn tracing off; deny the path |
| web.config compilation debug | Richer errors, extra surface | No | See framework debug |
| /phpinfo.php /actuator | Runtime / env dumps | No | Same class, other stacks |
When ELMAH still wins (off the public origin)
ELMAH as a library that writes to a private store still wins for operators. The miss is the public handler. trace.axd never belongs on a marketing host. Pair with server-status vs phpinfo if the same IIS box also publishes operator pages.
What the roast can prove
A 404 on /elmah.axd is not proof the handler is unregistered. Edge deny is cheap. Pair with framework debug if yellow pages still appear, and with exposed .env if the exception named connection strings.
Common mistakes
The first mistake is leaving ELMAH's handler mapped 'temporarily' on the brand hostname.
The second mistake is tracing enabled='true' in production web.config because local debugging needed it.
The third mistake is Disallow: /trace.axd and calling it access control.
Free audit the URL you own
RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.
Free audit nowFAQ
- Is ELMAH itself a vulnerability?
- Logging exceptions privately is fine. A world-readable error UI on the public origin is the miss.
- Does RoastMyOpsec fetch elmah.axd?
- Not as a scored path today. Deny /elmah.axd and /trace.axd on the public origin anyway.
- Is this only old Web Forms?
- Classic .axd names are Web Forms / System.Web. The class is any diagnostic UI: ELMAH, trace, phpinfo, Actuator. Same deny list.
Sources
Related guides
Vulnerabilities
Framework Debug Mode vs Verbose API ErrorsVulnerabilities
Apache server-status vs phpinfo() on ProductionVulnerabilities
.htaccess vs web.config on a Public Origin