펜리젠트 헤더

CVE-2025-55315, Kestrel Request Smuggling in ASP.NET Core

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

필드확인된 세부 정보중요한 이유
CVECVE-2025-55315Public identifier for the ASP.NET Core request smuggling issue.
영향을 받는 구성 요소ASP.NET Core Kestrel request parsingKestrel is the HTTP server used by ASP.NET Core applications.
취약성 등급HTTP request smugglingThe bug is about request boundary confusion, not a single application route.
CWECWE-444NVD maps the issue to inconsistent interpretation of HTTP requests.
PublishedOctober 14, 2025The advisory was published on Microsoft’s October 2025 Patch Tuesday.
CVSS 3.19.9 criticalMicrosoft’s vector is network, low complexity, low privilege, no user interaction, changed scope, high confidentiality and integrity impact, low availability impact.
Core attack conditionAmbiguous HTTP request parsingThe risk appears when malformed chunked requests are interpreted differently across components.
Primary security impactSecurity feature bypassAuthentication, authorization, routing, internal API access, and request manipulation may be affected depending on app design.
Fixed ASP.NET Core 8 version8.0.21Minimum patched runtime for .NET 8 lines listed by Microsoft.
Fixed ASP.NET Core 9 version9.0.10Minimum patched runtime for .NET 9 lines listed by Microsoft.
Fixed Kestrel.Core 2.x package2.3.6Required 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)

Chunked Transfer Encoding and Parser Desynchronization

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:

레이어Example componentSecurity decisions it may make
EdgeCDN, managed load balancer, cloud ingressTLS termination, IP filtering, bot filtering, routing
보안 계층WAF, API gateway, reverse proxyBlock rules, path restrictions, header normalization, auth handoff
Application entryKestrel, IIS integration, YARP, container ingressRequest parsing, protocol handling, connection reuse
MiddlewareASP.NET Core auth, routing, CSRF, rate limitingIdentity, authorization, request body access
Business logicControllers, minimal APIs, internal endpointsData access, file changes, state changes
Downstream servicesInternal APIs, metadata services, databasesPrivileged 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. (포트스위거)

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 Risk by Deployment Topology

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 또는 \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 그리고 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 그리고 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:

MetricCVSS valueMeaning in practice
공격 벡터네트워크The vulnerable component is reachable through network traffic.
Attack Complexity낮음The scoring assumes no unusual race or highly specialized environmental condition is required once the vulnerable condition exists.
필요한 권한낮음The attacker is authorized or has basic privileges, not necessarily administrator rights.
사용자 상호 작용없음No victim needs to click a link or perform an action for the base condition.
범위ChangedThe impact can cross a boundary beyond the vulnerable component.
기밀 유지높음Sensitive data may be exposed in severe scenarios.
무결성높음Unauthorized modification may be possible in severe scenarios.
Availability낮음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영향을 받는 버전Minimum patched version
ASP.NET Core 88.0.0 through 8.0.208.0.21
ASP.NET Core 99.0.0 through 9.0.99.0.10
ASP.NET Core 10 RC10.0.0 RC1 or earlier10.0.0 RC2 patched builds
Microsoft.AspNetCore.Server.Kestrel.Core 2.x2.3.0 or earlier in affected ASP.NET Core 2.x use2.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

다음을 찾아보세요. 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 patternRisk questionSafer posture
Kestrel directly exposed to the internetCan external clients send raw HTTP/1.1 chunked requests to KestrelPatch immediately and avoid direct exposure where possible.
CDN or WAF in front of KestrelDoes the edge normalize or reject malformed chunked bodiesPatch anyway and confirm edge behavior with vendor documentation and testing.
Reverse proxy to KestrelDoes the proxy forward ambiguous chunk extensions unchangedPatch Kestrel and configure proxy normalization or rejection where supported.
Azure App ServiceHas the platform front-end mitigation and app runtime update reached your appConfirm both platform notes and application runtime state.
Self-contained containerIs the vulnerable runtime embedded in the imageRebuild and redeploy the image from patched base layers.
Internal admin appCan low-privilege internal users or compromised hosts reach itTreat 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:

제어Why it helps
Reject malformed chunked requestsRemoves ambiguous streams before they reach Kestrel.
Normalize request bodies before forwardingReduces parser differences between layers.
Avoid forwarding both Content-Length 그리고 Transfer-EncodingPrevents classic request smuggling variants.
Strip untrusted identity headers at the edgePrevents attackers from injecting headers that the backend treats as trusted.
Add trusted identity headers only after authenticationKeeps identity provenance clear.
Prevent direct backend accessEnsures attackers cannot bypass the normalizing layer.
Use consistent HTTP versions between proxy and backend where feasibleReduces translation ambiguity, but only after compatibility testing.
Log request IDs at every hopHelps 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.ProtocolsHttpProtocols 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 Learn)

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:

PatternWhy it raises risk
Trusting proxy-injected identity headersA smuggled request may reach backend code with attacker-controlled or stale header context.
Protecting admin paths only at the proxyThe backend may process a hidden request that the proxy did not classify as the admin path.
Reading and forwarding raw request bodiesApplication-level proxy behavior can introduce additional parser boundaries.
Internal APIs reachable from the same backendA smuggled request may reach routes assumed to be internal-only.
Shared backend connectionsDesynchronization can affect request ordering and response association.
Cacheable responses behind edge cachesRequest confusion can become cache poisoning.
Weak CSRF or origin assumptionsHidden requests may bypass checks that depend on visible request structure.
Multi-tenant low-privilege accountsA 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:

단계액션증거
1Identify all ASP.NET Core apps and vendor products using ASP.NET CoreAsset list, runtime inventory, SBOM
2Determine deployment typeFramework-dependent, self-contained, container, managed platform
3Confirm runtime or package versionsdotnet --list-runtimes, image inspection, package lock files
4Patch and redeployChange record, new runtime output, build logs
5Confirm backend cannot be reached directlyNetwork policy, firewall rules, service exposure
6Review proxy behaviorVendor advisory, config, authorized lab test
7Check logs for suspicious patternsProxy logs, Kestrel logs, WAF logs, request IDs
8Retest with approved scopeEvidence 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. (펜리전트)

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:

신호Where to lookWhat it may indicate
Malformed chunked requestsWAF, reverse proxy, packet capture in authorized environmentsProbing or exploit attempts
Spikes in 400 responses after patchKestrel logsRejected malformed chunk extensions
Backend request with no matching edge requestCorrelated request IDsPossible desynchronization or direct backend access
Internal route hit from external flowApp logs, route logsProxy path filtering bypass or direct access
Unexpected identity headerApp logs, auth middleware telemetryHeader injection or trust-boundary issue
Multiple responses on one connectionLow-level proxy or lab captureParser desynchronization
Timeout on malformed chunked bodyLab validation logsPossible vulnerable parser behavior
Cache anomaliesCDN logs, cache keys, purge eventsRequest 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또는 /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-포워딩 대상, 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. (펜리전트)

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:

우선순위작업Done when
중요Inventory ASP.NET Core apps and vendor productsEvery internet-facing and internal app has an owner and runtime status.
중요Patch ASP.NET Core 8 to 8.0.21 or laterProduction runtime evidence confirms the fixed version.
중요Patch ASP.NET Core 9 to 9.0.10 or laterProduction runtime evidence confirms the fixed version.
중요Patch ASP.NET Core 10 RC deploymentsRC2 or later patched build is deployed.
중요Update Kestrel.Core 2.x package to 2.3.6Project files and built artifacts confirm the patched package.
중요Rebuild self-contained appsNew publish artifacts contain the patched runtime.
중요Rebuild container imagesRunning pods or containers show patched runtime versions.
높음Confirm backend is not directly reachableNetwork rules permit only intended proxy or ingress access.
높음Review proxy behaviorMalformed chunked requests are rejected or normalized by design.
높음Strip untrusted identity headersBackend identity context cannot be client-supplied.
높음Review raw body handlingAny request forwarding or manual stream parsing is documented and tested.
MediumAdd detection for malformed chunked requestsSecurity logs surface suspicious framing and backend mismatches.
MediumReview exposure windowSuspicious route access, file changes, token exposure, and cache anomalies are checked.
MediumRetest after patchEvidence 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.

참고 자료 및 추가 자료

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. (포트스위거)

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. (펜리전트)

Penligent, How to Get an AI Pentest Report. (펜리전트)

Penligent documentation and product overview for authorized AI-assisted penetration testing workflows. (펜리전트)

게시물을 공유하세요:
관련 게시물
ko_KRKorean