Aug 3, 2026·5 min read·4 visits
Improper query parameter serialization in Angular's HttpTransferCache yields identical cache keys for semantically different requests, allowing remote attackers to poison application states during SSR hydration.
An in-depth technical analysis of CVE-2026-68945, a high-severity security vulnerability in Angular's `@angular/common/http` package. The flaw stems from an ambiguity in how query parameters are serialized to generate cache keys during Server-Side Rendering (SSR) within the `HttpTransferCache` component. By failing to encode delimiters and implicitly coercing arrays to comma-joined strings, the serialization mechanism yields identical cache keys for distinct requests, facilitating State Poisoning and Cross-Request Response Reuse.
Angular applications employing Server-Side Rendering (SSR) often utilize the HttpTransferCache component inside the @angular/common/http package. This component serves as a performance optimization. When rendering a page on the server, the application serializes HTTP request-response pairs and embeds them in the HTML document. This metadata is transferred to the client, preventing duplicate HTTP requests during browser-side application hydration.
To identify and retrieve cached responses, the client-side hydration engine generates a deterministic cache key for each outgoing request. This key must uniquely represent the requested endpoint, including all associated query parameters. If the system generates the same cache key for two semantically distinct HTTP requests, the cache-key collision causes the client to reuse incorrect server-rendered data.
CVE-2026-68945 defines a critical flaw in this key-generation logic. The implementation in @angular/common/http allowed an unauthenticated remote attacker to generate colliding cache keys by structuring query parameters with specific delimiters or comma-separated arrays. This design flaw leads directly to Cross-Request Response Reuse and client-side State Poisoning.
The root cause of this vulnerability lies in the manual string serialization logic located within sortAndConcatParams in packages/common/http/src/transfer_cache.ts. Prior to the patch, the function mapped over the query parameter keys, sorted them, and converted key-value pairs into a string using the following logic:
${k}=${params.getAll(k)}
This implementation introduced two fundamental vulnerabilities. First, the logic relied on implicit array-to-string coercion. In JavaScript and TypeScript, interpolating an array (returned by params.getAll(k)) into a template string implicitly invokes Array.prototype.toString(). This joins the array elements with commas without escaping individual values. For example, a single scalar parameter containing a comma (?role=user,admin) produces the serialized output role=user,admin. Concurrently, a repeated parameter containing distinct values (?role=user&role=admin) returns ['user', 'admin'] from getAll, which also coerces to the identical output role=user,admin.
Second, the serialization logic failed to URL-encode the keys and values. Because ampersands (&) and equals signs (=) were not percent-encoded, an attacker could perform delimiter injection. A parameter key-value pair of a=1&b=2 would generate the serialized string fragment a=1&b=2. This output matches the serialization of a legitimate request with two discrete query parameters: a=1 and b=2.
The original, vulnerable implementation of the serialization helper function, along with the corrected logic introduced in the patch, highlights the shift from custom serialization to native standard APIs.
// VULNERABLE CODE PATH
function sortAndConcatParams(params: HttpParams | URLSearchParams): string {
return [...params.keys()]
.sort()
// params.getAll(k) returns string[], coerced via toString() to comma-separated values
.map((k) => `${k}=${params.getAll(k)}`)
.join('&');
}In the vulnerable scenario, sortAndConcatParams does not utilize safety utilities to sanitise characters like ,, &, or =. This allows structural manipulation of the serialized key structure.
// PATCHED CODE PATH
function sortAndConcatParams(params: HttpParams | URLSearchParams): string {
const searchParams = new URLSearchParams(
params instanceof URLSearchParams ? params : params.toString(),
);
searchParams.sort();
return searchParams.toString();
}The patch replaces the custom concatenation loop entirely. By instantiating a platform-native URLSearchParams object and sorting it via the native sort() method, Angular ensures that query parameter delimiters are correctly processed. The standard toString() method of URLSearchParams applies percent-encoding to commas, ampersands, and equal signs. Consequently, ?role=user,admin correctly serializes to role=user%2Cadmin, whereas ?role=user&role=admin serializes to role=user&role=admin, eliminating the key ambiguity.
Exploiting this flaw requires an Angular application that dynamically loads data during SSR based on query parameter input. An attacker targets the SSR engine to populate the cache with a crafted payload, which a victim subsequently retrieves via a normal application flow.
An attacker initiates a request to the application using a comma-separated format designed to mimic a multi-parameter administrative state. The SSR server processes the request and places a low-privilege or spoofed response in the cache with the serialized key role=user,admin. When a legitimate user loads the application using repeated parameters, the client-side hydration engine computes the cache key, gets a hit on the colliding entry, and hydrates the application with the attacker's cached state rather than performing a fresh backend API query.
The impact of CVE-2026-68945 is categorized as client-side State Poisoning and Cross-Request Response Reuse. If an application uses query parameters to determine authorization states, user contexts, or display content during SSR, this vulnerability can lead to security bypasses. An attacker can seed the server-side cache with unauthorized content that is subsequently presented to legitimate users.
In scenarios where the client relies on hydrated server responses to set user access levels or transaction details, the application's integrity is compromised. Because exploitation requires no authentication and can be performed remotely via standard network channels, the threat complexity is low. While it does not enable arbitrary server-side code execution, the high confidentiality impact and risk of data manipulation warrant the assigned CVSS score of 8.8.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@angular/common Angular | < 20.3.27 | 20.3.27 |
@angular/common Angular | >= 21.0.0-next.0, < 21.2.19 | 21.2.19 |
@angular/common Angular | >= 22.0.0-next.0, < 22.0.2 | 22.0.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-345 |
| Attack Vector | Network |
| CVSS Score | 8.8 |
| Exploit Status | Proof-of-Concept |
| Impact | State Poisoning / Cross-Request Response Reuse |
| KEV Status | Not Listed |
The application does not sufficiently verify that the received data matches the semantic intent of the client-side request.
A directory traversal and arbitrary file read vulnerability exists in PostCSS due to an incomplete fix of CVE-2026-45623. When parsing a CSS file containing a sourceMappingURL comment with the 'from' parameter unset, path traversal and absolute path validations are bypassed, enabling attackers to read arbitrary local .map files.
CVE-2026-69152 is a high-severity Denial of Service (DoS) vulnerability in brace-expansion that allows remote, unauthenticated attackers to cause a process crash or infinite thread-blocking condition. The vulnerability stems from a complete mitigation bypass of the security checks implemented for CVE-2026-14257.
A critical heap out-of-bounds (OOB) write vulnerability exists in the Linux kernel's IPv6 RPL (Routing Protocol for Low-Power and Lossy Networks) Segment Routing Header (SRH) processing logic. The vulnerability is located within net/ipv6/exthdrs.c, specifically in the ipv6_rpl_srh_rcv function. Under specific circumstances, when a packet containing a compressed RPL Source Routing Header is processed, segment swapping can reduce the common-prefix length, causing the recompressed header to grow. Because the kernel fails to validate available headroom on intermediate segments, a buffer underflow occurs during skb_push. This leads to an integer wrap in the MAC header offset pointer during MAC header rebuilding, causing a 14-byte out-of-bounds memory write roughly 64 KiB past the socket buffer.
CVE-2026-58263 is a high-severity Mutation Cross-Site Scripting (mXSS) vulnerability affecting Jodit Editor prior to version 4.12.28. The flaw exists in Jodit's built-in clean-html sanitizer plugin, which fails to securely parse and sanitize nested elements containing foreign namespaces like MathML and SVG. Attackers can bypass sanitization by smuggling malicious payload elements inside rawtext container tags like style inside a MathML node, leading to DOM mutation and unauthenticated arbitrary script execution in the context of the user's browser session.
Jodit Editor versions prior to 4.13.6 are vulnerable to client-side Cross-Site Scripting (XSS). The clean-html plugin's sanitization routine performs case-sensitive lookups against uppercase-only element blacklists. When processing XML-based foreign namespaces such as SVG or MathML, DOM engines preserve the lowercase format of tags. Because Jodit's denyTags check fails to normalize tag casing, malicious script blocks nested inside foreign namespace elements completely bypass validation and serialize directly into the editor output.
A critical code injection vulnerability exists in Savon, a widely used SOAP client library for Ruby, prior to version 2.17.2. The vulnerability resides within the Savon::Model.all_operations module, where operation names fetched from a target Web Services Description Language (WSDL) document are dynamically evaluated via module_eval without sanitization. An attacker capable of manipulating the target WSDL document (e.g., through Man-in-the-Middle attacks, DNS hijacking, or Server-Side Request Forgery) can execute arbitrary Ruby code in the context of the parent application process.