RoastMyOpsec

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.'

SurfaceTypical leakPublic originTakeaway
/elmah.axdException log, often request dataNoNot a scored roast path; deny anyway
/trace.axdRecent request tracesNoTurn tracing off; deny the path
web.config compilation debugRicher errors, extra surfaceNoSee framework debug
/phpinfo.php /actuatorRuntime / env dumpsNoSame 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 now

FAQ

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