Resources / Field guide

Fixing the most common DAST findings in ASP.NET

A security scan lands on your desk with a few hundred findings and a deadline. The good news: the volume is misleading — a handful of finding types usually account for the bulk of them, and most are straightforward to fix. Here's how to triage a DAST report and clear the ones that come up again and again.

Triage first: group, then count

A DAST report (WebInspect, ZAP, Burp, etc.) lists instances, which inflates the apparent size — one mistake repeated across 100 endpoints is 100 findings but one fix pattern. Group by finding type and sort by count, then bucket each type into one of three lanes:

  • Code fixes — controllers, filters, views, config you own. Your real work.
  • Infrastructure — TLS/cert and server config, handled outside the codebase.
  • Third-party / accepted risk — findings on services you don't control; document and accept with sign-off.

In practice a couple of types dominate the medium-severity count. Knock those out and the report shrinks dramatically.

Finding #1 — Sensitive data in GET query strings (Privacy Violation)

The most common offender: IDs, emails, tokens, and personal data passed in URLs. Query-string values leak into browser history, server and CDN access logs, and Referer headers — all outside the TLS-encrypted body. A URL like /account/sso?email=someone@example.com&customerId=42 writes a real email into every log it touches.

There are two sub-problems hiding here:

State-changing operations over GET (fix these first)

GET is reserved for safe, idempotent reads. An endpoint that deletes, updates, or archives via a GET query string is both a security finding and an HTTP-correctness bug (think pre-fetchers and crawlers firing your "delete" link). Move mutations to POST/PUT/DELETE with the data in the body, and protect them:

// Before: GET /orders/archive?id=42   (a crawler can trigger this)
// After:  a real mutation verb + anti-forgery
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Archive([FromBody] ArchiveRequest req) { /* … */ }

Sensitive reads over GET

For reads that legitimately need an identifier, keep opaque/non-sensitive values in the route (/orders/42) and move anything sensitive — emails, tokens, PII — into the request body or a server-side session/lookup rather than the query string. The goal is simple: nothing private should ever appear in a URL.

Finding #2 — Poor error handling (unhandled exceptions)

The second big bucket is exceptions that bubble up into a response, leaking stack traces and internals that help an attacker map your app. The fix is centralized: a global exception handler that logs the detail server-side and returns a generic, safe error to the client.

// Production: handle centrally, never show internals
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/error");   // logs detail, returns a safe page/response
    app.UseHsts();
}

Pair that with turning off detailed errors in production config, and make sure your error endpoint doesn't echo the exception. One handler clears a finding that's flagged on dozens of endpoints.

The usual supporting cast

  • Unprotected directories — block directory browsing and lock down any path that shouldn't be public (config).
  • Cross-frame scripting / clickjacking — send X-Frame-Options / a frame-ancestors CSP directive so your pages can't be framed by others.
  • Weak TLS / cert hostname mismatch — infrastructure: fix the certificate and disable weak protocols/ciphers at the server.
  • Cookie flags — set Secure, HttpOnly, and an appropriate SameSite on auth cookies; document any persistent-cookie finding you're accepting.

Make the report repeatable. After fixing, re-scan and diff against the baseline so you can prove the count dropped. For findings you're accepting (third-party, by design), write a one-line justification each — auditors want a decision, not silence.

The mindset

A scary-looking DAST report is mostly a handful of patterns repeated. Group by type, fix the few that dominate (almost always GET-query-string data and exception leakage), handle the config items, and explicitly accept what you can't control. Done methodically, "hundreds of vulnerabilities" becomes an afternoon of focused, satisfying work.

Have a security scan you need to clear?

I triage and remediate DAST/pen-test findings in ASP.NET apps — fixes, re-scan, and a clean justification for anything accepted. Let's get your report to green.

Work with me