← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:10993 · CWE-200 · Disclosed 2002-01-01

Microsoft ASP

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is leaving the mechanic's diagnostic screen facing the street instead of locking the hood

This finding is not a classic vendor-patched software bug so much as an ASP.NET configuration exposure. If an application has tracing enabled and the trace.axd viewer is reachable remotely, an unauthenticated user can pull recent request traces, which may include internal file paths, headers, cookies, session identifiers, form values, and server variables. Microsoft documents application tracing for classic ASP.NET on .NET Framework, with the trace viewer available at /trace.axd; the risky state is when tracing is on and localOnly is effectively not protecting it.

Tenable tags it Medium, but for enterprise prioritization that overstates the usual outcome. The decisive friction is impact: this is typically reconnaissance and incidental secret leakage, not direct code execution or privilege escalation, and it only exists where admins or developers left tracing exposed in production. Because the scanner has already proven reachability on the target, it is not ignorable, but most environments should treat it as LOW-severity hardening debt with real follow-on risk, not an emergency patch event.

"Public trace.axd is sloppy and useful to attackers, but it is usually a narrow info leak, not a breach by itself."
02 · The Attack Path

3 steps from start to impact.

STEP 01

Find the exposed trace viewer

An attacker uses a browser, curl, ffuf, or a scanner such as Nessus to request /trace.axd at the application root. If application tracing is enabled and remotely viewable, the endpoint returns a trace dashboard with recent requests and links to per-request details.
Conditions required:
  • The target runs classic ASP.NET on .NET Framework
  • Tracing is enabled for the application or page scope
  • trace.axd is reachable from the attacker's network position
Where this breaks in practice:
  • ASP.NET tracing is off by default
  • localOnly defaults to true, which should block remote viewing
  • Many modern reverse proxies and WAFs already block obvious diagnostic paths
Detection/coverage: Excellent scanner coverage. Nessus, Acunetix, and web DAST products detect this reliably because it is a simple HTTP content check.
STEP 02

Harvest high-value request metadata

Using the built-in trace viewer or a proxy such as Burp Suite, the attacker reviews recent requests and per-request details. Useful artifacts can include physical file paths, cookies, session IDs, request parameters, headers, stack context, and sometimes application-specific secrets accidentally logged during troubleshooting.
Conditions required:
  • Victim traffic has recently hit the application
  • The trace buffer still contains useful requests
Where this breaks in practice:
  • Trace history is finite and may contain only low-value noise
  • Well-designed apps avoid logging credentials or bearer tokens here
  • Short session lifetimes or binding controls reduce reuse of leaked identifiers
Detection/coverage: Web logs should show GETs to /trace.axd; very few legitimate external users ever need this path, so alerting can be high-signal.
STEP 03

Turn leakage into access or better recon

The attacker attempts follow-on use of stolen artifacts with standard HTTP tooling or a proxy. In the best case for the attacker, a reusable session token or privileged workflow leak enables session hijack; in the more common case, the output simply improves targeting for later phishing, auth attacks, path probing, or exploit chaining.
Conditions required:
  • Leaked data must include something operationally reusable
  • The target application must lack compensating controls such as session binding or strong re-authentication
Where this breaks in practice:
  • Most leaked details are contextual rather than immediately weaponizable
  • MFA, re-auth, device checks, and session binding can break token reuse
  • Internal paths and stack details help attackers, but they do not compromise the host by themselves
Detection/coverage: No signature guarantees detection of the follow-on stage. Success depends on what was leaked, so downstream suspicious session reuse and unusual request sequences are better indicators than the trace request alone.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo CISA KEV entry and no public evidence of a named exploitation campaign tied to this specific exposure. What *is* common is commodity reconnaissance for trace.axd on internet-facing IIS/ASP.NET sites.
Proof-of-concept availabilityTrivial. No exploit framework is needed; a browser or curl https://target/trace.axd is enough if the endpoint is exposed.
EPSSN/A. This finding is not tracked here as a CVE-backed software flaw, so there is no FIRST EPSS score to anchor on.
KEV statusNot listed. There is no corresponding CVE entry in CISA KEV for trace.axd exposure.
CVSS / vendor scoringTenable labels the plugin Medium but does not publish a CVSS vector/score on the plugin page. In practice this behaves like a narrow confidentiality exposure with high environmental dependency.
Affected scopeClassic ASP.NET / .NET Framework applications where tracing is enabled and remotely viewable. Microsoft documents the trace viewer at /trace.axd; remote exposure requires tracing plus permissive localOnly behavior.
Default-safe behaviorMicrosoft's TraceSection.LocalOnly documentation shows DefaultValue=true, and tracing itself is documented as disabled by default. That sharply reduces the affected population versus a vendor-patched RCE.
Fixed stateThere is no patched software version to chase. The safe state is configuration: disable tracing in production or keep it local-only and inaccessible from untrusted networks.
Scanning / exposure dataExposure is easy to verify and scanners have strong coverage because the issue is just a reachable diagnostic endpoint. Internet prevalence is environment-dependent; scanners such as Tenable, Acunetix, and ScanRepeat all publish checks for it.
Disclosure / attributionTenable records a vulnerability publication date of 2002-01-01 and plugin publication on 2002-06-05. There is no clear public researcher attribution because this is a long-known insecure deployment pattern, not a newly disclosed vendor bug.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to LOW (3.8/10)

The single most important downgrading factor is that this is usually a configuration-only information leak with no direct code execution path. Even though the endpoint is remotely reachable when present, the real-world impact depends on what recent traces happen to contain and whether leaked session material is actually reusable.

HIGH This is a real exposure when the scanner confirms `/trace.axd` is remotely accessible
HIGH Default deployment friction is substantial because tracing is off by default and `localOnly` defaults to true
MEDIUM Actual business impact varies widely based on whether traces contain reusable secrets or privileged session context

Why this verdict

  • Downgrade for impact ceiling: this is usually information disclosure and attacker recon, not initial remote code execution or host takeover.
  • Downgrade for exposure population: the app must be both tracing-enabled and remotely viewable; Microsoft documents defaults that are safer than the exposed state.
  • Downgrade for chain dependency: weaponizing leaked session IDs, cookies, or paths usually requires additional weakness in session handling, logging hygiene, or app design.

Why not higher?

There is no direct exploit primitive here comparable to RCE, auth bypass, or arbitrary file read. The attacker gets value only if the trace buffer happens to include sensitive material and that material can be reused before it expires or is otherwise invalidated.

Why not lower?

This is still an unauthenticated remote disclosure on a production web application, and the scanner has already shown the endpoint is reachable. Internal paths, headers, and live session context are exactly the sort of crumbs attackers use to shorten later attack chains, so it deserves cleanup rather than documentation-only dismissal.

05 · Compensating Control

What to do — in priority order.

  1. Block /trace.axd at the edge — Add an explicit deny rule in the reverse proxy, WAF, or IIS request filtering layer so remote clients cannot fetch the diagnostic endpoint. For a LOW verdict there is no SLA and this should be handled as backlog hygiene, but internet-facing apps should still get the block during the next normal web change window because it is cheap and high-value.
  2. Disable application tracing in production — Set tracing off in the effective web.config for production applications unless a narrow support need justifies it. There is no formal mitigation deadline for LOW findings, so fold this into the next standard application configuration release and make it part of deployment baselines.
  3. Force localOnly=true if tracing must stay on — If operations insists on tracing for break-fix support, keep the viewer restricted to localhost and only for the shortest possible maintenance period. For a LOW finding this is backlog hygiene rather than an emergency action, but it should be enforced before the next production troubleshooting cycle.
  4. Monitor for requests to the path — Create high-signal alerts for any request to /trace.axd, especially from external source ranges, because legitimate use is rare. This can be implemented in the next logging or WAF policy update and helps catch both scanning and accidental exposure.
What doesn't work
  • Relying on obscurity or non-linked URLs does not help; scanners probe trace.axd directly.
  • Changing only the page output behavior is not enough; pageOutput=false can still leave the trace viewer accessible.
  • Generic EDR on the web server does not prevent the disclosure because the problem happens inside normal HTTP responses.
  • Assuming HTTPS solves it is wrong; TLS protects transport, not unauthorized visibility of diagnostic data.
06 · Verification

Crowdsourced verification payload.

Run this on the target IIS/ASP.NET host in an elevated PowerShell session so it can enumerate IIS sites and read application web.config files. Invoke it as powershell -ExecutionPolicy Bypass -File .\check-traceaxd.ps1; admin rights are recommended, and the script outputs VULNERABLE, PATCHED, or UNKNOWN with per-site details.

noisgate-verify.ps1
POWERSHELLREAD-ONLYSAFE
# check-traceaxd.ps1

# Purpose: Detect remotely risky ASP.NET trace.axd exposure in IIS applications.

# Logic: Enumerate IIS sites/apps, parse web.config, and flag VULNERABLE if trace is enabled and localOnly is not true.

# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN


$ErrorActionPreference = 'Stop'

function Resolve-PhysicalPath {
    param([string]$Path)
    if ([string]::IsNullOrWhiteSpace($Path)) { return $null }
    if ($Path -match '^%') {
        return [Environment]::ExpandEnvironmentVariables($Path)
    }
    return $Path
}

function Get-TraceStateFromConfig {
    param([string]$ConfigPath)

    $result = [ordered]@{
        ConfigPath = $ConfigPath
        Enabled    = $null
        LocalOnly  = $null
        State      = 'UNKNOWN'
        Note       = ''
    }

    if (-not (Test-Path -LiteralPath $ConfigPath)) {
        $result.Note = 'web.config not found'
        return [pscustomobject]$result
    }

    try {
        [xml]$xml = Get-Content -LiteralPath $ConfigPath -Raw
        $traceNode = $xml.SelectSingleNode('/configuration/system.web/trace')

        if ($null -eq $traceNode) {
            $result.State = 'PATCHED'
            $result.Note  = 'No <trace> element found; application-level tracing not explicitly enabled here'
            return [pscustomobject]$result
        }

        $enabledAttr   = $traceNode.GetAttribute('enabled')
        $localOnlyAttr = $traceNode.GetAttribute('localOnly')

        if (-not [string]::IsNullOrWhiteSpace($enabledAttr)) {
            $result.Enabled = $enabledAttr
        }
        if (-not [string]::IsNullOrWhiteSpace($localOnlyAttr)) {
            $result.LocalOnly = $localOnlyAttr
        }

        $enabled = $false
        if ($enabledAttr) {
            [void][bool]::TryParse($enabledAttr, [ref]$enabled)
        }

        # Microsoft default is localOnly=true when the attribute is omitted.

        $localOnly = $true
        if ($localOnlyAttr) {
            [void][bool]::TryParse($localOnlyAttr, [ref]$localOnly)
        }

        if ($enabled -and (-not $localOnly)) {
            $result.State = 'VULNERABLE'
            $result.Note  = 'Tracing enabled and remotely viewable (localOnly=false)'
        }
        elseif ($enabled -and $localOnly) {
            $result.State = 'PATCHED'
            $result.Note  = 'Tracing enabled but restricted to localhost (not remotely exposed)'
        }
        else {
            $result.State = 'PATCHED'
            $result.Note  = 'Tracing disabled'
        }

        return [pscustomobject]$result
    }
    catch {
        $result.State = 'UNKNOWN'
        $result.Note  = ('Failed to parse web.config: ' + $_.Exception.Message)
        return [pscustomobject]$result
    }
}

try {
    Import-Module WebAdministration -ErrorAction Stop
}
catch {
    Write-Output 'UNKNOWN - Could not load WebAdministration module. Run on an IIS host with admin rights.'
    exit 2
}

$findings = @()

try {
    $sites = Get-Website
}
catch {
    Write-Output 'UNKNOWN - Could not enumerate IIS websites.'
    exit 2
}

foreach ($site in $sites) {
    try {
        $apps = Get-WebApplication -Site $site.Name -ErrorAction SilentlyContinue
        $allApps = @()

        # Root application for the site

        $rootPath = Resolve-PhysicalPath $site.physicalPath
        $allApps += [pscustomobject]@{
            SiteName      = $site.Name
            AppPath       = '/'
            PhysicalPath  = $rootPath
        }

        foreach ($app in $apps) {
            $appPath = Resolve-PhysicalPath $app.PhysicalPath
            $allApps += [pscustomobject]@{
                SiteName     = $site.Name
                AppPath      = $app.Path
                PhysicalPath = $appPath
            }
        }

        foreach ($appEntry in $allApps) {
            if ([string]::IsNullOrWhiteSpace($appEntry.PhysicalPath)) {
                $findings += [pscustomobject]@{
                    Site       = $appEntry.SiteName
                    AppPath    = $appEntry.AppPath
                    ConfigPath = ''
                    State      = 'UNKNOWN'
                    Enabled    = $null
                    LocalOnly  = $null
                    Note       = 'Could not resolve physical path'
                }
                continue
            }

            $cfg = Join-Path $appEntry.PhysicalPath 'web.config'
            $trace = Get-TraceStateFromConfig -ConfigPath $cfg

            $findings += [pscustomobject]@{
                Site       = $appEntry.SiteName
                AppPath    = $appEntry.AppPath
                ConfigPath = $cfg
                State      = $trace.State
                Enabled    = $trace.Enabled
                LocalOnly  = $trace.LocalOnly
                Note       = $trace.Note
            }
        }
    }
    catch {
        $findings += [pscustomobject]@{
            Site       = $site.Name
            AppPath    = '/'
            ConfigPath = ''
            State      = 'UNKNOWN'
            Enabled    = $null
            LocalOnly  = $null
            Note       = ('Enumeration failure: ' + $_.Exception.Message)
        }
    }
}

$findings | ForEach-Object {
    $enabledText = if ($null -ne $_.Enabled) { $_.Enabled } else { '<default/unspecified>' }
    $localOnlyText = if ($null -ne $_.LocalOnly) { $_.LocalOnly } else { '<default=true/unspecified>' }
    Write-Output ("[{0}] Site='{1}' App='{2}' Enabled='{3}' LocalOnly='{4}' Config='{5}' Note='{6}'" -f $_.State, $_.Site, $_.AppPath, $enabledText, $localOnlyText, $_.ConfigPath, $_.Note)
}

if ($findings.State -contains 'VULNERABLE') {
    Write-Output 'VULNERABLE'
    exit 1
}
elseif (($findings | Where-Object { $_.State -eq 'PATCHED' }).Count -gt 0 -and -not ($findings.State -contains 'UNKNOWN')) {
    Write-Output 'PATCHED'
    exit 0
}
else {
    Write-Output 'UNKNOWN'
    exit 2
}
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: treat this as web hardening cleanup, not a stop-the-world patch fire. Because the reassessed severity is LOW, there is no noisgate mitigation SLA and no noisgate remediation SLA beyond backlog hygiene; translate that into one concrete action: block or disable exposed trace.axd during the next routine web change window, verify no production app still has tracing remotely viewable, and document any exception owners so this does not get reintroduced in later deployments.

Sources

  1. Tenable Nessus Plugin 10993
  2. Microsoft Learn - ASP.NET Tracing Overview
  3. Microsoft Learn - View ASP.NET Trace Information with the Trace Viewer
  4. Microsoft Learn - TraceSection.LocalOnly Property
  5. CIS Microsoft IIS Benchmark excerpt on ASP.NET tracing
  6. Acunetix - ASP.NET application-level tracing enabled
  7. ScanRepeat - Trace.axd Information Leak
  8. MITRE CWE-200
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.