CVE-2025-55315 is a critical HTTP request smuggling vulnerability in ASP.NET Core’s Kestrel web server. Microsoft released security updates for it on October 14, 2025. The official description is short but important: inconsistent interpretation of HTTP requests in ASP.NET Core can allow an authorized attacker to bypass a security feature over the network. NVD records the issue as CWE-444, Inconsistent Interpretation of HTTP Requests, and lists Microsoft’s CVSS 3.1 vector as AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L, with a 9.9 critical base score. (Microsoft)
The practical reading is more precise than “Kestrel equals instant RCE.” Request smuggling is a boundary confusion bug. It becomes dangerous when one component in the HTTP chain thinks a byte stream contains one request while another component sees an additional request hidden inside it. In a real ASP.NET Core deployment, that disagreement can interact with reverse proxies, WAFs, authentication middleware, proxy-injected identity headers, internal routes, SSRF controls, cache layers, and application code that reads or forwards raw request bodies. Microsoft’s own explanation says the hidden request can affect authentication and authorization decisions and can enable request manipulation depending on how the application processes requests. (Microsoft)
For defenders, the first move is not payload hunting. It is inventory and patching. ASP.NET Core 8 applications must run 8.0.21 or later, ASP.NET Core 9 applications must run 9.0.10 or later, ASP.NET Core 10 release-candidate deployments must move to the patched RC2 builds, and older ASP.NET Core 2.x applications consuming Microsoft.AspNetCore.Server.Kestrel.Core need the patched 2.3.6 package. Self-contained deployments are not fixed just because the host machine has a newer runtime. They must be rebuilt and redeployed. Microsoft’s GitHub advisory states that applications using affected runtimes, SDKs, or affected packages are exposed and that self-contained applications targeting impacted versions must be recompiled and redeployed. (GitHub)
CVE-2025-55315 at a glance
| Feld | Verified detail | Warum das wichtig ist |
|---|---|---|
| CVE | CVE-2025-55315 | Public identifier for the ASP.NET Core request smuggling issue. |
| Betroffene Komponente | ASP.NET Core Kestrel request parsing | Kestrel is the HTTP server used by ASP.NET Core applications. |
| Klasse der Anfälligkeit | HTTP request smuggling | The bug is about request boundary confusion, not a single application route. |
| CWE | CWE-444 | NVD maps the issue to inconsistent interpretation of HTTP requests. |
| Published | October 14, 2025 | The advisory was published on Microsoft’s October 2025 Patch Tuesday. |
| CVSS 3.1 | 9.9 critical | Microsoft’s vector is network, low complexity, low privilege, no user interaction, changed scope, high confidentiality and integrity impact, low availability impact. |
| Core attack condition | Ambiguous HTTP request parsing | The risk appears when malformed chunked requests are interpreted differently across components. |
| Primary security impact | Security feature bypass | Authentication, authorization, routing, internal API access, and request manipulation may be affected depending on app design. |
| Fixed ASP.NET Core 8 version | 8.0.21 | Minimum patched runtime for .NET 8 lines listed by Microsoft. |
| Fixed ASP.NET Core 9 version | 9.0.10 | Minimum patched runtime for .NET 9 lines listed by Microsoft. |
| Fixed Kestrel.Core 2.x package | 2.3.6 | Required when an older ASP.NET Core 2.x app consumes the standalone Kestrel.Core package. |
The affected version ranges are not speculative. Microsoft’s advisory lists ASP.NET Core 10.0 RC1 or earlier, ASP.NET Core 9.0.9 or earlier, ASP.NET Core 8.0.20 or earlier, and ASP.NET Core 2.x applications consuming Microsoft.AspNetCore.Server.Kestrel.Core 2.3.0 or earlier. NVD’s enrichment also lists affected ASP.NET Core 8.0.0 to before 8.0.21, ASP.NET Core 9.0.0 to before 9.0.10, ASP.NET Core 2.3.0 to before 2.3.6, and several Visual Studio 2022 version ranges. (GitHub)

What Microsoft fixed in CVE-2025-55315
HTTP request smuggling is old, but CVE-2025-55315 matters because it sits inside a platform component that many teams do not think of as part of their application security boundary. Kestrel is not just plumbing. It decides where one request ends and the next one begins. When that decision is ambiguous, everything above it becomes easier to confuse.
Microsoft’s public MSRC post explains the issue as an ASP.NET Core vulnerability that allows HTTP request smuggling. It describes a crafted request that can hide another request inside it and says that, depending on how the application processes requests, the result could include privilege escalation or request manipulation. The same post emphasizes that the CVSS score reflects severe potential impact, especially for sensitive or regulated environments, even though not every application will be exploitable in the same way. (Microsoft)
The original GitHub advisory is more operational. It states that Microsoft released the advisory for ASP.NET Core 10.0, 9.0, 8.0, and 2.3, and that inconsistent interpretation of HTTP requests in ASP.NET Core allows an authorized attacker to bypass a security feature over the network. It also says Microsoft had not identified mitigating factors for the vulnerability at publication time. That last sentence matters. It means teams should not treat “we have a proxy” or “we have a WAF” as a substitute for patching unless the proxy’s behavior has been specifically validated. (GitHub)
The technical center of the fix is stricter parsing. In the public technical analysis by Andrew Lock, the issue is tied to how Kestrel handled chunk extensions in chunked transfer encoding. Before the fix, the parser’s approach to ignoring chunk extensions could allow ambiguity around line endings. The patch changes Kestrel so that invalid line endings in chunk extension parsing are rejected rather than tolerated. When the fixed parser sees a line ending that is not strict CRLF in the relevant place, it throws a bad-request exception and returns a 400 response instead of drifting into a state that can support smuggling. (Andrew Lock | .NET Escapades)
That is the right shape of a request smuggling fix. The secure behavior is not to guess what the client meant. The secure behavior is to reject malformed request framing before application code, middleware, caches, or authorization logic have to reason about it.
Why HTTP request smuggling breaks real deployments
Most web applications are not a single server receiving a clean request from a browser. A typical production path looks more like this:
| Ebene | Example component | Security decisions it may make |
|---|---|---|
| Edge | CDN, managed load balancer, cloud ingress | TLS termination, IP filtering, bot filtering, routing |
| Sicherheitsebene | WAF, API gateway, reverse proxy | Block rules, path restrictions, header normalization, auth handoff |
| Application entry | Kestrel, IIS integration, YARP, container ingress | Request parsing, protocol handling, connection reuse |
| Middleware | ASP.NET Core auth, routing, CSRF, rate limiting | Identity, authorization, request body access |
| Business logic | Controllers, minimal APIs, internal endpoints | Data access, file changes, state changes |
| Downstream services | Internal APIs, metadata services, databases | Privileged operations and sensitive data |
Request smuggling attacks live in the gap between these layers. If the edge or proxy sees one request but the backend sees two, the second request can bypass checks that were supposed to happen before it reached application code. PortSwigger’s Web Security Academy describes request smuggling as exploiting discrepancies between front-end and back-end systems in how they process HTTP request sequences. In practice, that can let an attacker interfere with another user’s requests, bypass front-end security controls, poison caches, or reach internal functionality that was never meant to be directly exposed. (PortSwigger)
This is why request smuggling is not limited to “bad headers.” It is a desynchronization problem. The front end and back end lose agreement about the stream. Once that happens, security controls that depend on that agreement may become unreliable.
A common example is a proxy that performs access control before forwarding traffic. The proxy blocks /admin, strips untrusted identity headers, or adds trusted headers after mutual TLS. The backend application then assumes those checks already happened. If a smuggled request reaches the backend without being seen by the proxy in the same way, the backend may process a request that the proxy would have rejected.
Another example is cache poisoning. If the front end associates a response with one visible request while the backend generated that response from a different hidden request, cached content can be corrupted. That does not require remote code execution. It requires enough confusion to make the wrong response look legitimate in the wrong context.
A third example is credential exposure. Request smuggling can sometimes be used to prefix or poison the next user’s request on a reused connection. That class of attack is highly dependent on connection reuse, timing, and application behavior, but it is one reason request smuggling bugs can have impact beyond a single attacker-controlled request.
Chunked transfer encoding is the quiet part of CVE-2025-55315

CVE-2025-55315 is tied to HTTP/1.1 chunked transfer encoding. Chunked transfer encoding lets a client send a request body in pieces when it does not know the full body size in advance. Instead of sending one Content-Length, the client sends Transfer-Encoding: chunked, then a series of chunks. Each chunk has a size line, the chunk data, and a CRLF terminator. A zero-size chunk marks the end of the body.
A simplified chunked body looks like this:
POST /upload HTTP/1.1
Host: example.test
Transfer-Encoding: chunked
Content-Type: text/plain
5
hello
6
world
0
That example is harmless. The important point is that the server must parse the chunk boundaries exactly. If one component thinks a chunk ended earlier than another component does, the remaining bytes may be treated as either body data or a new request.
HTTP chunk extensions make the parsing surface larger. A chunk size line can include optional metadata after a semicolon. The metadata is not delivered to application code as request body data. It is protocol-level metadata attached to the chunk. Jeppe Bonde Weikop’s June 2025 “Funky chunks” research explains that chunk extensions are part of RFC 9112 and that servers generally ignore them because real clients rarely use them for meaningful application behavior. That “ignore it” mindset is exactly where parser bugs tend to appear. (w4ke.info)
A chunk extension looks like this:
e;foo=bar
some more data
The application usually does not care about foo=bar. The parser still has to consume it correctly. The safe parser does not simply scan forward until something vaguely looks like a line break. It must enforce the allowed syntax and reject invalid framing.
The security issue appears when components disagree about what counts as a valid line ending inside or around chunk extensions. HTTP chunk lines are supposed to use CRLF. A lone LF or lone CR inside a chunk extension is not a valid chunk-line terminator. Weikop’s research describes how parsers may choose one of three behaviors when they encounter an unusual newline in a chunk extension: treat it as ordinary invalid extension data and keep searching, interpret it as a line terminator, or reject the request. Only rejection is the consistently safe behavior when the syntax is invalid. (w4ke.info)
That distinction sounds small until two components make different choices. If a proxy treats a lone LF as the end of the chunk header while Kestrel treats it differently, or the reverse, they no longer agree on how many bytes belong to the first request. That is the core of the desynchronization.
Chunk extensions and bad line endings
A safe way to understand the bug is to think in terms of parser states, not exploit strings. The parser reads a request line, headers, a blank line, then a body. For Transfer-Encoding: chunked, the body has its own mini-language:
chunk-size [optional chunk extension] CRLF
chunk-data CRLF
chunk-size [optional chunk extension] CRLF
chunk-data CRLF
0 CRLF
CRLF
Every transition matters. The parser must know whether it is reading a chunk size, extension metadata, chunk data, or the end marker. If the parser accepts malformed line endings in one state, it may move into the next state too early or too late.
Andrew Lock’s analysis explains that the CVE-2025-55315 variant relies on Transfer-Encoding and chunk extensions. The key ambiguity is how a parser treats standalone \r oder \n in a chunk header. Correct implementations must reject those characters in that position. Differences between proxy and server behavior create a request smuggling condition. (Andrew Lock | .NET Escapades)
A conceptual example looks like this:
front end view:
request A body continues until the zero-size chunk
hidden bytes are treated as body data
back end view:
request A ends earlier
remaining bytes are parsed as request B
The dangerous result is not that the attacker sent strange bytes. The dangerous result is that the front end and back end attach different meanings to the same bytes.
This is also why generic security advice such as “block requests with both Content-Length and Transfer-Encoding” is not enough. Traditional request smuggling often focuses on Content-Length und Transfer-Encoding confusion. Chunk extension smuggling can use a different parser discrepancy. The W4ke research specifically notes that these techniques do not rely on forwarding both Content-Length und Transfer-Encoding; they rely on chunked body parsing and line terminator ambiguity. (w4ke.info)
A patched parser should reject malformed chunk extension syntax before the request reaches application code. A normalizing proxy may also reduce risk if it fully parses and rewrites the body into an unambiguous representation. But partial normalization is dangerous. A proxy chain can still contain multiple components, and each component may have different tolerance rules.
Why the CVSS 9.9 score is serious but context dependent
The 9.9 score caused confusion because people read it as “every ASP.NET Core app is one step from total compromise.” That is not the right conclusion. The right conclusion is that the platform bug can undermine application-level security decisions in severe ways when the deployment and app logic create exploitable conditions.
Microsoft’s MSRC post says the score reflects the importance of promptly addressing a security feature bypass that can influence how applications enforce authentication and authorization. It also says the issue can enable techniques such as privilege escalation or request manipulation depending on request processing. That is carefully scoped language. It does not promise the same exploit path against every app. (Microsoft)
The CVSS vector explains the severity assumptions:
| Metrisch | CVSS value | Meaning in practice |
|---|---|---|
| Angriffsvektor | Netzwerk | The vulnerable component is reachable through network traffic. |
| Attack Complexity | Niedrig | The scoring assumes no unusual race or highly specialized environmental condition is required once the vulnerable condition exists. |
| Erforderliche Privilegien | Niedrig | The attacker is authorized or has basic privileges, not necessarily administrator rights. |
| Interaktion mit dem Benutzer | Keine | No victim needs to click a link or perform an action for the base condition. |
| Umfang | Changed | The impact can cross a boundary beyond the vulnerable component. |
| Vertraulichkeit | Hoch | Sensitive data may be exposed in severe scenarios. |
| Integrität | Hoch | Unauthorized modification may be possible in severe scenarios. |
| Availability | Niedrig | Some availability impact is possible, but it is not the dominant risk. |
The “low privileges required” detail is especially important. It means a logged-in low-privilege user may be enough in some scenarios. That still matters for SaaS apps, admin portals, partner dashboards, internal tools, and bug bounty targets. A low-privilege account is often easy to obtain. If request smuggling lets that account reach a privileged internal route, override a trusted header, or manipulate a request processed under another context, the real-world impact can be far higher than the account’s normal permissions.
At the same time, exploitability is not automatic. An app that has patched Kestrel, does not expose the vulnerable runtime, does not trust proxy-injected identity headers from untrusted paths, strictly authorizes every endpoint in application code, avoids raw request forwarding, and has a normalizing proxy that rejects malformed chunked requests has a very different risk profile from an app that depends on edge-only authorization and runs an unpatched self-contained deployment.
Affected ASP.NET Core versions and what to patch
The most reliable way to handle CVE-2025-55315 is to treat it as a runtime and deployment inventory problem. Microsoft’s advisory gives the patch targets clearly:
| Runtime or package line | Betroffene Versionen | Minimum patched version |
|---|---|---|
| ASP.NET Core 8 | 8.0.0 through 8.0.20 | 8.0.21 |
| ASP.NET Core 9 | 9.0.0 through 9.0.9 | 9.0.10 |
| ASP.NET Core 10 RC | 10.0.0 RC1 or earlier | 10.0.0 RC2 patched builds |
| Microsoft.AspNetCore.Server.Kestrel.Core 2.x | 2.3.0 or earlier in affected ASP.NET Core 2.x use | 2.3.6 |
Microsoft’s GitHub advisory also states that if an application references a vulnerable package, the package reference must be updated, and if the application is self-contained, it must be recompiled and redeployed. (GitHub)
Checking the runtime on a server is straightforward:
dotnet --info
dotnet --list-runtimes
Suche nach Microsoft.AspNetCore.App entries:
dotnet --list-runtimes | grep Microsoft.AspNetCore.App
A fixed .NET 8 host should show Microsoft.AspNetCore.App 8.0.21 or later. A fixed .NET 9 host should show Microsoft.AspNetCore.App 9.0.10 or later.
For Windows servers using the ASP.NET Core Hosting Bundle, verify the installed bundle version through your software inventory, PowerShell, or endpoint management tooling. For Linux servers, verify the package source and installed runtime packages. For containerized apps, checking the host is not enough. You need to inspect the image and the runtime inside the container:
docker run --rm your-image:tag dotnet --list-runtimes
For Kubernetes, create a short-lived debug run or inspect the running pod:
kubectl exec -n prod deploy/your-aspnet-app -- dotnet --list-runtimes
For self-contained apps, dotnet --list-runtimes on the host can be misleading because the vulnerable runtime is bundled into the application publish directory. Check how the app was built:
grep -R "<SelfContained>true</SelfContained>" -n .
grep -R "<RuntimeIdentifier>" -n .
grep -R "<RuntimeIdentifiers>" -n .
If the app was published self-contained against a vulnerable runtime, rebuild it with a patched SDK/runtime and redeploy the artifact. Do not assume a server-level runtime update changes a self-contained binary.
For old ASP.NET Core 2.x projects using the Kestrel.Core package directly, inspect the project file:
grep -R "Microsoft.AspNetCore.Server.Kestrel.Core" -n .
Then update the package:
dotnet add package Microsoft.AspNetCore.Server.Kestrel.Core --version 2.3.6
dotnet restore
dotnet build
Microsoft’s advisory lists the patched Kestrel.Core package version as 2.3.6 and provides both Visual Studio and .NET CLI update paths. (GitHub)
Do not forget Visual Studio and developer machines
NVD lists several Visual Studio 2022 affected version ranges in its enrichment data, including versions from 17.10.0 to before 17.10.20, 17.12.10 to before 17.12.13, and 17.14.0 to before 17.14.17. That does not mean a developer IDE is usually your internet-facing Kestrel server. It means the platform and SDK distribution chain matters. Build machines, CI images, developer workstations, and publish agents may all carry older SDKs or templates. (NVD)
The mistake to avoid is upgrading production but leaving CI pinned to a vulnerable SDK image that keeps producing self-contained vulnerable builds. A safe CI check should fail builds when the resolved runtime is below the fixed version.
A simple example for a Linux CI job:
set -euo pipefail
dotnet --list-runtimes
if dotnet --list-runtimes | grep -E "Microsoft.AspNetCore.App 8\.0\.(0|1|2|3|4|5|6|7|8|9|1[0-9]|20)\b"; then
echo "Blocked: ASP.NET Core 8 runtime is below 8.0.21"
exit 1
fi
if dotnet --list-runtimes | grep -E "Microsoft.AspNetCore.App 9\.0\.(0|1|2|3|4|5|6|7|8|9)\b"; then
echo "Blocked: ASP.NET Core 9 runtime is below 9.0.10"
exit 1
fi
That check is intentionally simple. Mature environments should use SBOM data, container image scanning, package inventory, and deployment evidence. The goal is not to win a regex contest. The goal is to prevent vulnerable runtime versions from reappearing after the emergency patch window.
Deployment patterns that change the risk
CVE-2025-55315 risk changes with topology. The same vulnerable Kestrel version can have different practical exposure depending on how traffic reaches it.
| Deployment pattern | Risk question | Safer posture |
|---|---|---|
| Kestrel directly exposed to the internet | Can external clients send raw HTTP/1.1 chunked requests to Kestrel | Patch immediately and avoid direct exposure where possible. |
| CDN or WAF in front of Kestrel | Does the edge normalize or reject malformed chunked bodies | Patch anyway and confirm edge behavior with vendor documentation and testing. |
| Reverse proxy to Kestrel | Does the proxy forward ambiguous chunk extensions unchanged | Patch Kestrel and configure proxy normalization or rejection where supported. |
| Azure App Service | Has the platform front-end mitigation and app runtime update reached your app | Confirm both platform notes and application runtime state. |
| Self-contained container | Is the vulnerable runtime embedded in the image | Rebuild and redeploy the image from patched base layers. |
| Internal admin app | Can low-privilege internal users or compromised hosts reach it | Treat internal reachability as real exposure, especially for admin paths. |
Azure App Service is a useful example of why platform details matter. The Azure App Service team said it deployed a patch to its HTTP load balancer infrastructure to mitigate CVE-2025-55315 and that the patch protects Web Apps, Function Apps, and Logic Apps Standard on both Windows and Linux instances even if the underlying .NET runtime remains on an affected version. It also said the infrastructure patch moves the front-end layer to the latest available framework so malicious content is filtered before reaching customer app instances. (Azure GitHub)
That is a platform-specific mitigation, not a universal rule. It should not be generalized to every proxy, every ingress, or every managed hosting provider.
QNAP’s NetBak PC Agent advisory shows a different kind of dependency risk. QNAP said NetBak PC Agent installs and depends on Microsoft ASP.NET Core components during setup, so computers running the agent may contain affected ASP.NET Core versions if the system has not been updated. QNAP recommended reinstalling the latest agent or manually updating the ASP.NET Core Runtime Hosting Bundle, noting 8.0.21 as the latest version as of October 2025. (QNAP)
That pattern matters for enterprise asset owners. You may not think you “run ASP.NET Core,” but a vendor product may install it.
Reverse proxies are useful but not a substitute for patching
A reverse proxy can reduce exposure if it strictly parses request bodies, rejects invalid chunked encoding, normalizes body framing, and prevents direct backend access. But a reverse proxy can also be part of the problem. Request smuggling requires two parties to disagree. A proxy that is more tolerant than the backend, or less tolerant in a different way, can create exploitable desynchronization.
The safest proxy posture is:
| Kontrolle | Why it helps |
|---|---|
| Reject malformed chunked requests | Removes ambiguous streams before they reach Kestrel. |
| Normalize request bodies before forwarding | Reduces parser differences between layers. |
Avoid forwarding both Content-Length und Transfer-Encoding | Prevents classic request smuggling variants. |
| Strip untrusted identity headers at the edge | Prevents attackers from injecting headers that the backend treats as trusted. |
| Add trusted identity headers only after authentication | Keeps identity provenance clear. |
| Prevent direct backend access | Ensures attackers cannot bypass the normalizing layer. |
| Use consistent HTTP versions between proxy and backend where feasible | Reduces translation ambiguity, but only after compatibility testing. |
| Log request IDs at every hop | Helps detect front-end and backend disagreement. |
Do not assume a WAF signature alone solves CVE-2025-55315. A WAF may not inspect the decrypted body if TLS terminates elsewhere. It may normalize in one direction but forward ambiguity in another. It may be bypassed through an internal load balancer or direct pod service. It may also lack visibility into backend connection reuse, which is often where request smuggling consequences show up.
Kestrel itself can be configured for different HTTP protocols through endpoint protocol settings, and Microsoft’s documentation describes ListenOptions.Protocols und die HttpProtocols enum for Kestrel endpoints. Protocol restrictions can be useful in controlled architectures, but they are not the primary fix for CVE-2025-55315. The primary fix is the patched parser. Protocol changes should be treated as architecture hardening and tested for compatibility with clients, proxies, and hosting platforms. (Microsoft Lernen)
Application patterns that raise exploit impact
The highest-risk applications are not merely those that run a vulnerable Kestrel version. They are applications that place important trust decisions at a boundary that request smuggling can confuse.
High-risk patterns include:
| Pattern | Why it raises risk |
|---|---|
| Trusting proxy-injected identity headers | A smuggled request may reach backend code with attacker-controlled or stale header context. |
| Protecting admin paths only at the proxy | The backend may process a hidden request that the proxy did not classify as the admin path. |
| Reading and forwarding raw request bodies | Application-level proxy behavior can introduce additional parser boundaries. |
| Internal APIs reachable from the same backend | A smuggled request may reach routes assumed to be internal-only. |
| Shared backend connections | Desynchronization can affect request ordering and response association. |
| Cacheable responses behind edge caches | Request confusion can become cache poisoning. |
| Weak CSRF or origin assumptions | Hidden requests may bypass checks that depend on visible request structure. |
| Multi-tenant low-privilege accounts | A low-privilege tenant user can be a realistic starting point. |
Microsoft’s MSRC post calls out applications that parse raw requests manually, rely on headers for security decisions, or skip validation based on request structure as examples of apps that should review configuration and apply the update. (Microsoft)
A common insecure pattern looks like this:
app.Use(async (context, next) =>
{
// Dangerous if this header is trusted without proving it came from a trusted proxy.
var userFromProxy = context.Request.Headers["X-Authenticated-User"].ToString();
if (!string.IsNullOrEmpty(userFromProxy))
{
context.Items["UserName"] = userFromProxy;
}
await next();
});
A safer design strips untrusted inbound versions of those headers at the edge, adds trusted identity context only after authentication, restricts who can connect to the backend, and still performs endpoint-level authorization in application code. The application should not treat the mere presence of a header as proof of identity.
For ASP.NET Core applications behind proxies, be careful with forwarded headers. Only trust forwarded headers from known proxies and networks. Do not accept arbitrary X-Forwarded-* or identity-like headers from the public internet.
A safer conceptual pattern:
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
options.KnownProxies.Add(IPAddress.Parse("10.0.0.10"));
});
That example does not fix CVE-2025-55315. It reduces a related class of trust-boundary mistakes that can make request smuggling more damaging.
Safer validation for CVE-2025-55315
The supported safety check is version-based. If the deployed ASP.NET Core runtime or package is patched, the Kestrel parser contains the fix. If it is not patched, assume exposure until proven otherwise.
A responsible validation workflow looks like this:
| Schritt | Aktion | Beweise |
|---|---|---|
| 1 | Identify all ASP.NET Core apps and vendor products using ASP.NET Core | Asset list, runtime inventory, SBOM |
| 2 | Determine deployment type | Framework-dependent, self-contained, container, managed platform |
| 3 | Confirm runtime or package versions | dotnet --list-runtimes, image inspection, package lock files |
| 4 | Patch and redeploy | Change record, new runtime output, build logs |
| 5 | Confirm backend cannot be reached directly | Network policy, firewall rules, service exposure |
| 6 | Review proxy behavior | Vendor advisory, config, authorized lab test |
| 7 | Check logs for suspicious patterns | Proxy logs, Kestrel logs, WAF logs, request IDs |
| 8 | Retest with approved scope | Evidence bundle and replayable notes |
In production, avoid improvised payload testing against live user-facing services unless the scope, timing, rate limits, and rollback plan are explicit. Request smuggling tests can affect connection state and other users if performed carelessly. If active probing is required, do it in a maintenance window or a controlled replica first.
A safe local lab can verify parser behavior without touching a real target. The test pattern is to run a vulnerable and patched Kestrel app in isolation, send a malformed chunked request, and observe whether the parser rejects the malformed framing. Public proofs of concept demonstrate this class of behavior by comparing vulnerable and patched responses, but production validation should be based on your own authorized environment and should avoid turning a detection check into an exploit attempt. The CISA-ADP referenced gist shows a vulnerable server producing two responses on the same TCP connection and a patched build preventing the smuggled request by rejecting the bad chunk extension. (Gist)
For teams responsible for many web applications, the hard part is rarely writing one probe. It is preserving scope, proving which assets were tested, tying each result to a runtime version, capturing enough evidence for engineering, and retesting after deployment. Penligent’s public product material describes workflows around launching security tools, scanning for CVEs, generating one-click PoC scripts, preserving evidence-first results, and producing traceable proof. In a CVE-2025-55315 response, that kind of workflow is most useful when it stays inside authorized scope and turns runtime inventory, safe validation, and retest evidence into a reproducible record rather than a one-off scanner output. (Sträflich)
Detection and telemetry that actually help
Request smuggling is difficult to detect because the defining symptom is disagreement. The proxy may log one request. The backend may log two. The WAF may show a blocked or allowed request that does not match what the application processed. A normal access log line can miss the important part.
Useful detection starts with correlated logs across layers:
| Signal | Where to look | What it may indicate |
|---|---|---|
| Malformed chunked requests | WAF, reverse proxy, packet capture in authorized environments | Probing or exploit attempts |
| Spikes in 400 responses after patch | Kestrel logs | Rejected malformed chunk extensions |
| Backend request with no matching edge request | Correlated request IDs | Possible desynchronization or direct backend access |
| Internal route hit from external flow | App logs, route logs | Proxy path filtering bypass or direct access |
| Unexpected identity header | App logs, auth middleware telemetry | Header injection or trust-boundary issue |
| Multiple responses on one connection | Low-level proxy or lab capture | Parser desynchronization |
| Timeout on malformed chunked body | Lab validation logs | Possible vulnerable parser behavior |
| Cache anomalies | CDN logs, cache keys, purge events | Request confusion or poisoning attempt |
On patched Kestrel, malformed chunk extension requests should be rejected early. Andrew Lock’s analysis notes that the fix causes Kestrel to throw KestrelBadHttpRequestException and return a 400 response when it finds invalid line endings rather than strict CRLF. (Andrew Lock | .NET Escapades)
If your logs include exception categories, look for bad request exceptions around malformed chunked encoding. If you terminate TLS at the edge, inspect edge and proxy logs for malformed request framing. If your IDS only sees encrypted traffic, it will not detect HTTP body-level patterns unless deployed at a point where traffic is decrypted.
A cautious Suricata-style detection idea for decrypted HTTP inspection might look for Transfer-Encoding: chunked combined with suspicious control characters inside chunk extension syntax. This is not a drop-in universal rule. It needs testing against your traffic, your parser, and your false-positive tolerance.
alert http any any -> $HOME_NET any (
msg:"Possible malformed HTTP chunk extension probing";
flow:to_server,established;
content:"Transfer-Encoding|3a| chunked"; http_header;
pcre:"/\\r\\n[0-9a-fA-F]+;[^\\r\\n]*(\\x0a|\\x0d[^\\x0a])/s";
classtype:web-application-attack;
sid:5531501;
rev:1;
)
The point of a rule like that is not to prove exploitation. It is to surface suspicious malformed chunk extension traffic for correlation with runtime versions, backend logs, and request IDs.
For application-level telemetry, add route, user, tenant, and request ID context to security-sensitive operations. If a low-privilege user suddenly triggers an admin-only route, you need to know which edge request, backend request, identity context, and connection produced it.
Patch and redeploy without missing the real runtime
A clean remediation plan should handle each deployment model separately.
For framework-dependent Linux hosts:
dotnet --list-runtimes
# Use your distribution or Microsoft package source to update.
# Example shape only, exact package names vary by distro:
sudo apt-get update
sudo apt-get install aspnetcore-runtime-8.0
dotnet --list-runtimes
sudo systemctl restart your-app.service
For Windows servers using the Hosting Bundle, install the patched ASP.NET Core Runtime Hosting Bundle, then restart the application pool, service, or host process. Microsoft’s advisory tells users to install the latest .NET 8.0 or .NET 9.0 and restart apps for the update to take effect. (GitHub)
For self-contained deployment:
dotnet --info
dotnet publish ./src/YourApp/YourApp.csproj \
-c Release \
-r linux-x64 \
--self-contained true \
-o ./publish/linux-x64
./publish/linux-x64/YourApp --version
Then deploy the new artifact. The old artifact remains vulnerable if it bundled the vulnerable runtime.
For containers, update the base image and rebuild:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY ./publish/ .
ENTRYPOINT ["dotnet", "YourApp.dll"]
Then verify inside the image:
docker build -t your-app:patched .
docker run --rm your-app:patched dotnet --list-runtimes
For multi-stage builds, update both SDK and runtime images. A patched runtime image with an old SDK stage may still be acceptable for framework-dependent apps, but self-contained publishing depends on what the SDK resolves and bundles. Keep both updated unless you have a documented reason not to.
For Kubernetes, do not stop at pushing a new image. Confirm the rollout:
kubectl rollout status deployment/your-app -n prod
kubectl exec -n prod deploy/your-app -- dotnet --list-runtimes
Then confirm that no old pods remain:
kubectl get pods -n prod -l app=your-app -o wide
If you use horizontal pod autoscaling, jobs, background workers, blue-green deployments, or canary stacks, check all of them. Old pods and old job images are common sources of incomplete remediation.
Hardening ASP.NET Core after the patch
Patching CVE-2025-55315 removes the known Kestrel parser flaw. Hardening reduces the chance that a future parser or proxy mismatch becomes a severe application compromise.
The most important hardening rule is to keep authorization inside the application. Edge authorization is useful, but backend routes should still enforce their own authorization checks. A request should not become privileged merely because it reached the backend.
A minimal endpoint-level pattern:
app.MapGet("/admin/users", async (HttpContext context) =>
{
// Admin-only logic
return Results.Ok();
})
.RequireAuthorization("AdminOnly");
A policy definition:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireRole("Admin");
});
});
Do not rely on proxy path filtering as the only control for /admin, /internal, /debug, /actuator, /metrics, oder /ops routes. If the backend route can perform a privileged action, the backend should enforce privilege.
Second, strip and reissue trusted headers at the edge. Headers such as X-Forwarded-For, X-Forwarded-Proto, X-Authenticated-User, X-SSL-CLIENT-CN, and custom identity headers should not be accepted directly from the public client. The edge should remove inbound versions and add trusted versions only after authentication and validation.
Third, prevent direct backend reachability. Kestrel should not be reachable from the public internet if it is meant to sit behind a proxy. Use security groups, Kubernetes network policies, private subnets, and firewall rules to ensure the only inbound path is through the intended edge.
A Kubernetes network-policy shape:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-only-from-gateway
namespace: prod
spec:
podSelector:
matchLabels:
app: aspnet-api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress
ports:
- protocol: TCP
port: 8080
Fourth, avoid unnecessary raw request stream manipulation. Microsoft’s MSRC post explicitly calls out applications that parse raw requests manually as a condition worth reviewing. If your application reads HttpRequest.Body, rewrites it, forwards it, or implements proxy-like behavior, treat that code as a security boundary. (Microsoft)
Fifth, make cache keys security-aware. A cache that ignores authentication state, host, scheme, tenant, or critical headers can turn request confusion into persistent content confusion. Caches should not store sensitive authenticated responses unless the variation rules are explicit and tested.
Sixth, make malformed request rejection visible. After patching, 400 responses for malformed chunked requests can be useful security telemetry. Do not bury them entirely in noise. Aggregate counts by source, route, edge node, backend node, and time window.
Incident response when exposure was real
If an internet-facing or low-trust internal ASP.NET Core app ran a vulnerable version, treat the response as more than a patch ticket. The right depth depends on exposure, business criticality, and application design.
Start with the exposure window. Identify the first deployment date of the vulnerable runtime and the time the patched runtime was confirmed in production. Include containers, self-contained artifacts, secondary regions, staging environments with production data, and vendor products that installed ASP.NET Core components.
Then map entry points. List every route reachable through the vulnerable app, every proxy in front of it, every internal route that the proxy was supposed to block, and every header the backend trusted from the proxy. This is where architecture diagrams matter. A request smuggling issue is rarely understood from a package list alone.
Next, review logs for boundary anomalies:
edge request count != backend request count
backend admin route hit without matching edge admin route
backend request has trusted identity header from unexpected source
same connection produces unusual request sequence
low-privilege user touches high-privilege route
sensitive route receives malformed or missing CSRF context
Also check file integrity and state-changing operations. Microsoft and QNAP both describe potential outcomes that include unauthorized access to sensitive data, file modification, and limited denial-of-service conditions in severe scenarios. Those are not guaranteed outcomes, but they define what a serious investigation should look for. (Microsoft)
If session tokens, API tokens, service credentials, or internal admin cookies could have been exposed through request confusion, rotate them. Rotation is especially important if logs show suspicious access to account pages, token endpoints, internal metadata routes, admin APIs, or file-management features during the exposure window.
Finally, preserve evidence. A useful CVE response record should include affected versions, asset list, patch evidence, test scope, logs reviewed, suspicious events found or not found, remediation actions, and retest results. Penligent’s writing on AI pentest reports makes a useful point for this kind of response: a credible security report needs scope, reproducible evidence, exploit conditions, impact, remediation, and retest context, not just polished prose. That standard applies to CVE-2025-55315 remediation as much as it applies to a full pentest deliverable. (Sträflich)
Related CVEs that show the broader parser problem
CVE-2025-55315 is part of a larger pattern: HTTP parser leniency becomes security debt when requests pass through multiple components.
CVE-2025-58056 affected Netty’s HTTP/1.1 chunk extension parsing. The Netty advisory says a flaw in parsing chunk extensions in chunked HTTP/1.1 messages can lead to request smuggling with some reverse proxies. Specifically, Netty interpreted LF as the end of the chunk-size line even without a preceding CR, violating the HTTP/1.1 requirement for CRLF. The patched versions are 4.1.125.Final and 4.2.5.Final. (GitHub)
That is highly relevant because the underlying lesson is almost identical: one HTTP implementation accepts a malformed line ending in a chunk extension, another component handles it differently, and the disagreement can create a second request boundary.
CVE-2025-53643 affected aiohttp. NVD describes it as a request smuggling vulnerability in aiohttp prior to 3.12.14 due to the Python parser not parsing trailer sections of an HTTP request. The advisory says exploitation may allow an attacker to bypass certain firewall or proxy protections when the pure Python parser is used or AIOHTTP_NO_EXTENSIONS is enabled. (NVD)
That is not the same bug as CVE-2025-55315, but it belongs to the same family. The parser, proxy, and backend disagree about request structure. The security impact depends on what boundary that disagreement crosses.
CVE-2024-52304, also in aiohttp, is another relevant example because it involved incorrect parsing of newlines in chunk extensions. Public advisory data describes it as request smuggling due to wrong parsing of chunk extensions under certain conditions. (GitHub)
The differences in severity across these advisories should not be surprising. A parser bug in a library is not scored only by grammar theory. It is scored by privileges required, attack conditions, deployment patterns, reachable impact, and downstream security assumptions. Microsoft scored CVE-2025-55315 as severe because ASP.NET Core applications can build important authentication and authorization decisions on top of Kestrel’s request parsing boundary. Netty’s advisory rated its issue low, while still acknowledging request smuggling with some reverse proxies. (NVD)
The security engineering lesson is not “all request smuggling CVEs are equally critical.” The lesson is “HTTP parser differentials must be tested in the architecture where they run.”
Common mistakes during CVE-2025-55315 remediation
The first mistake is calling the issue a universal unauthenticated RCE. That is inaccurate. Microsoft describes a security feature bypass through HTTP request smuggling. Some downstream application behaviors could lead to severe outcomes, but the CVE itself should be described precisely. (Microsoft)
The second mistake is patching developer machines and forgetting production. dotnet --info on a laptop does not prove the runtime inside a production container, Windows service, Linux VM, App Service instance, or self-contained publish directory.
The third mistake is ignoring self-contained deployments. Microsoft explicitly states that self-contained applications targeting impacted versions are vulnerable and must be recompiled and redeployed. (GitHub)
The fourth mistake is treating a reverse proxy as a magic shield. A proxy can help only if it rejects or normalizes the relevant malformed requests and if attackers cannot reach Kestrel directly. In request smuggling, the proxy is often one side of the parsing disagreement.
The fifth mistake is testing only the homepage. Request smuggling impact often appears through protected routes, internal APIs, state-changing endpoints, caches, or connection reuse. A simple GET / check cannot prove the absence of application impact.
The sixth mistake is failing to preserve evidence. A patch ticket that says “updated .NET” is not enough for a critical CVE. You need runtime proof, deployment proof, scope proof, and retest proof.
The seventh mistake is trusting identity headers without provenance. If an application treats X-User, X-Role, X-SSL-CLIENT-CN, or any custom auth header as authoritative, the edge must strip inbound versions and the backend must only accept those headers from a trusted path.
The eighth mistake is assuming internal means safe. Many damaging request smuggling paths begin from a low-privilege internal account, a partner VPN, a compromised workstation, or a staging environment connected to real services.
A practical remediation checklist
Use this as the minimum operational checklist for CVE-2025-55315:
| Priorität | Task | Done when |
|---|---|---|
| Kritisch | Inventory ASP.NET Core apps and vendor products | Every internet-facing and internal app has an owner and runtime status. |
| Kritisch | Patch ASP.NET Core 8 to 8.0.21 or later | Production runtime evidence confirms the fixed version. |
| Kritisch | Patch ASP.NET Core 9 to 9.0.10 or later | Production runtime evidence confirms the fixed version. |
| Kritisch | Patch ASP.NET Core 10 RC deployments | RC2 or later patched build is deployed. |
| Kritisch | Update Kestrel.Core 2.x package to 2.3.6 | Project files and built artifacts confirm the patched package. |
| Kritisch | Rebuild self-contained apps | New publish artifacts contain the patched runtime. |
| Kritisch | Rebuild container images | Running pods or containers show patched runtime versions. |
| Hoch | Confirm backend is not directly reachable | Network rules permit only intended proxy or ingress access. |
| Hoch | Review proxy behavior | Malformed chunked requests are rejected or normalized by design. |
| Hoch | Strip untrusted identity headers | Backend identity context cannot be client-supplied. |
| Hoch | Review raw body handling | Any request forwarding or manual stream parsing is documented and tested. |
| Mittel | Add detection for malformed chunked requests | Security logs surface suspicious framing and backend mismatches. |
| Mittel | Review exposure window | Suspicious route access, file changes, token exposure, and cache anomalies are checked. |
| Mittel | Retest after patch | Evidence includes version proof and authorized validation results. |
The final state should be boring: patched runtime, rebuilt artifacts, no direct backend exposure, strict request parsing, no blind trust in proxy headers, and evidence that another engineer can verify.
References and further reading
Microsoft MSRC, Understanding CVE-2025-55315. (Microsoft)
Microsoft GitHub advisory for CVE-2025-55315 in ASP.NET Core. (GitHub)
NVD record for CVE-2025-55315. (NVD)
GitHub Advisory Database entry for GHSA-5rrx-jjjq-q2r5. (GitHub)
Jeppe Bonde Weikop, Funky chunks research on ambiguous chunk line terminators. (w4ke.info)
PortSwigger Web Security Academy, HTTP request smuggling. (PortSwigger)
Andrew Lock, technical analysis of CVE-2025-55315 and Kestrel chunk extension parsing. (Andrew Lock | .NET Escapades)
Azure App Service platform mitigation note for CVE-2025-55315. (Azure GitHub)
QNAP advisory for ASP.NET Core dependency exposure in NetBak PC Agent. (QNAP)
Netty advisory for CVE-2025-58056, request smuggling due to incorrect parsing of chunk extensions. (GitHub)
NVD record for CVE-2025-53643 in aiohttp. (NVD)
Penligent, Codex for White-Box Audits, Black-Box Pentesting for Proof. (Sträflich)
Penligent, How to Get an AI Pentest Report. (Sträflich)
Penligent documentation and product overview for authorized AI-assisted penetration testing workflows. (Sträflich)

