Sep 17, 2026·5 min read·11 visits
Unsanitized logging of request query parameters in Steeltoe's HttpExchanges actuator endpoint leaks secrets (OAuth tokens, API keys) in memory and debug log files to unauthorized actors.
Steeltoe, a popular framework for building cloud-native .NET applications, contains a critical data-exposure flaw in its HttpExchanges actuator endpoint before version 4.3.0. When explicitly configured to include query strings, the system records and stores sensitive values (such as OAuth tokens and credentials) in memory and application debug logs without sanitization, exposing them to unauthorized network actors.
The Steeltoe.Management.Endpoint framework provides telemetry and diagnostic utilities for cloud-native .NET applications. One of these utilities, the HTTP Exchanges Actuator (/actuator/httpexchanges), monitors and records historical details about HTTP requests and responses passing through the application. This diagnostic information is designed to assist administrators in monitoring application traffic and diagnosing connectivity issues.
However, a severe information disclosure flaw exists within versions of Steeltoe preceding version 4.3.0. When the HTTP Exchanges actuator is exposed and configured to include query parameters via the Management:Endpoints:HttpExchanges:IncludeQueryString = true setting, the framework fails to sanitize or mask sensitive arguments passed inside the request URI.
This lack of sanitization exposes systems to CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor). If the endpoint is left unauthenticated or poorly restricted, any network-adjacent actor can query the actuator and read operational secrets. Furthermore, when the framework's debug-level logger is enabled, the unmasked URIs are also written to application log files in cleartext, resulting in secondary credential leakage.
The root cause of this vulnerability lies in the design and implementation of the internal MaskedUri structure within Steeltoe's common extensions. When the actuator captures request payloads, it attempts to pass the target URI through MaskedUri to strip sensitive information before storing the transaction in an in-memory buffer.
In the legacy codebase, the MaskedUri constructor only performed sanitization on the UserInfo subcomponent of the URI, which is the basic-authentication block containing username:password in the authority segment. The masking routine completely ignored the query string section of the URI. If the basic-authentication credentials were not present, the masking function immediately returned the raw URI object without modifying or parsing its query parameters.
Additionally, the evaluation of the MaskedUri struct was deferred until JSON serialization. The HttpExchangeRequest component stored the raw, unmasked Uri instance directly in the application's memory pool. This storage mechanism allowed other application tasks, such as internal diagnostic logging routines written via LogIncomingExchange, to read and print the raw, unmasked query parameter data directly into persistent debug log files.
The official patch introduced in commit 9bf0ecb9f2d4a34b65f61d41c5625d49071ae9fa refactored the masking logic. It implemented a robust substring matching filter against query keys and shifted the execution of URI masking to the initiation step of the HttpExchangeRequest class, completely eliminating the deferred evaluation issue.
In the legacy implementation, the masking check was bypassed if UserInfo was empty:
// Legacy vulnerable masking logic in MaskedUri.cs
private static Uri Mask(Uri source)
{
if (string.IsNullOrEmpty(source.UserInfo))
{
return source; // Query parameters were skipped entirely
}
var builder = new UriBuilder(source)
{
UserName = "****",
Password = "****"
};
return builder.Uri;
}The updated implementation performs proactive masking of both UserInfo and sensitive query-string values through substring analysis:
// Patched logic in MaskedUri.cs
internal static Uri Mask(Uri source)
{
bool hasUserInfo = !string.IsNullOrEmpty(source.UserInfo);
string? maskedQueryString = MaskQueryString(source.Query);
if (!hasUserInfo && maskedQueryString == null)
{
return source;
}
var builder = new UriBuilder(source);
if (hasUserInfo)
{
builder.UserName = "****";
builder.Password = "****";
}
if (maskedQueryString != null)
{
builder.Query = maskedQueryString;
}
return builder.Uri;
}The MaskQueryString function parses the query components using HttpUtility.ParseQueryString and compares the keys against a pre-compiled array of sensitive terms (such as "pass", "pwd", "key", "token", "secret", "auth", "hash", "sig"). If any query key contains one of these terms, its value is immediately overwritten with asterisks.
Exploiting this vulnerability requires specific configuration and active network traffic but no prior user privileges. An attacker first scans the application surface to confirm the presence of Steeltoe actuator interfaces. If /actuator/httpexchanges is exposed, the attacker can verify if query-string recording is active.
During normal operation, legitimate clients perform activities that transmit short-lived or permanent credentials over the URL, such as password reset routines (/reset?token=XYZ), API gateway calls (/api?api_key=XYZ), or OAuth 2.0 redirection flows containing authorization codes. When these requests are processed by the server, the unsanitized URIs are logged directly into the application's memory storage buffer.
To retrieve the captured parameters, the attacker sends a standard GET request to the exchanges actuator endpoint:
GET /actuator/httpexchanges HTTP/1.1
Host: target.internal.netThe target application responds with a JSON payload containing transaction records. The attacker parses the returned request.uri entries to extract operational keys. Armed with these credentials, the attacker can perform account takeover, session hijacking, or escalate privileges within administrative APIs.
While the sanitization patch introduced in version 4.3.0 mitigates the immediate credential exposure risk, security teams should remain aware of potential bypass paths. The masking mechanism relies on a static, predefined blacklist of query key substrings. If developers transmit credentials using atypical parameter names that do not match the blacklist (such as ?id=, ?session=, or custom, company-specific keys), the values will pass through unsanitized.
Additionally, this logic only sanitizes URL query parameters. If credentials are split into standard RESTful path components (such as /api/v1/auth/session-abc1234/profile) rather than query arguments, the path-cleansing routine will not isolate or mask them. This limitation means path-based session tokens remain exposed to memory capturing and downstream log analysis.
Organizations must also ensure that POST and PUT body fields are handled securely, as the HttpExchanges actuator sanitization does not inspect request request bodies. For robust operational security, endpoints handling sensitive transaction states should migrate authentication metadata entirely to HTTP headers.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Steeltoe.Management.Endpoint SteeltoeOSS | < 4.3.0 | 4.3.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-200, CWE-532 |
| Attack Vector | Network |
| CVSS v3.1 Score | 5.9 (Medium) |
| Exploit Status | poc |
| CISA KEV Status | No |
| Attack Complexity | High |
| Impact | High (Information Disclosure) |
The product exposes sensitive information to an actor who is not authorized to have access to that information.
CVE-2026-118777 is a prototype pollution vulnerability (CWE-1321) in the Forge JavaScript cryptography and networking library (distributed on npm as node-forge) prior to version 1.4.1. The flaw resides in the forge.http client subsystem, where incoming HTTP cookie names and paths parsed from Set-Cookie response headers are stored directly into standard JavaScript objects without key validation or property isolation. By returning crafted Set-Cookie headers containing keys such as __proto__ or constructor, a malicious HTTP server can inject arbitrary properties into Object.prototype, attach attributes to the global Object constructor, or delete built-in prototype methods to cause an application-wide denial of service.
CVE-2026-118775 (GHSA-4642-5mcj-2rqw) is an integer overflow and validation flaw in the ASN.1 serialization module of Forge (node-forge) prior to version 1.4.1. The asn1.oidToDer() function fails to validate the range of the first two arcs of an Object Identifier (OID) and truncates the packed initial subidentifier to a single 8-bit integer. Applications that perform policy checks on untrusted OID strings before encoding them into Distinguished Encoding Rules (DER) format can be tricked into emitting DER bytes that correspond to a completely different, restricted OID.
CVE-2026-119194 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting versions 0.3.3 through 0.6.4. The flaw resides in the schemaless decoding routine ConstructedPayloadDecoderBase._decodeComponentsSchemaless used across BER, CER, and DER codecs. By sending an ASN.1 container populated with child components whose tag identifiers are separated by multiples of CPython's integer hash modulus (sys.hash_info.modulus), an unauthenticated attacker can force worst-case hash collisions in an unbounded Python set, degrading decoding performance from O(N) to O(N^2) and causing a Denial of Service (DoS).
CVE-2026-119195 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting all versions prior to 0.6.5. When decoding constructed strings or indefinite-length ANY types across BER, CER, and certain DER code paths, the payload decoders repeatedly concatenate incoming fragments onto an immutable bytes object using the += operator. Because Python bytes objects cannot be resized in-place, each fragment iteration allocates a new buffer and copies all previously accumulated bytes, resulting in quadratic O(N^2) time and memory copy complexity. An unauthenticated remote attacker can supply a highly fragmented ASN.1 stream to exhaust CPU cycles and stall application worker threads.
An algorithmic complexity vulnerability (CWE-407) in pyasn1 versions prior to 0.6.5 allows unauthenticated attackers to cause a Denial of Service (DoS) via crafted ASN.1 payloads. The flaw resides in the binary-encoded ASN.1 REAL mantissa deserialization routine within RealPayloadDecoder.valueDecoder. By performing iterative byte-string slicing and repeated bitwise shifts on a growing arbitrary-precision integer, the decoder exhibits quadratic time and memory allocation complexity relative to the mantissa length. Supplying a BER-, CER-, or DER-encoded payload with a large REAL mantissa causes excessive CPU consumption and blocks application worker processes.
A vulnerability classified under CWE-407 (Inefficient Algorithmic Complexity) exists in the pyasn1 library prior to version 0.6.5. When parsing constructed ASN.1 BIT STRING payloads under BER, CER, or schema-driven DER encoding rules, the BitStringPayloadDecoder repeatedly shifts and copies the entire accumulated bit value for each incoming fragment. Processing inputs with a large number of small constructed fragments induces quadratic CPU consumption, allowing unauthenticated remote attackers to cause a denial of service via resource exhaustion during the initial decoding phase.