Oct 3, 2026·6 min read·10 visits
A stack overflow vulnerability in the aws-smithy-json token-skipping function allows unauthenticated remote attackers to crash Smithy-rs generated servers via deeply nested JSON payloads.
CVE-2026-18140 is a denial-of-service vulnerability in the Amazon aws-smithy-json Rust crate. Under-validation of recursion depth within the unknown-key skipping path allows a remote, unauthenticated attacker to cause stack exhaustion and process aborts by sending deeply nested JSON arrays.
The aws-smithy-json crate is a foundational component of smithy-rs, a framework used to automatically generate HTTP client and server runtimes in Rust from Smithy service models. This package implements low-level parsing routines for parsing structured JSON requests and responses. It exposes a direct attack surface to unauthenticated endpoints that consume JSON.
The vulnerability exists in the mechanisms used to deserialize payloads. When a Smithy-rs generated server processes incoming JSON, it relies on a token-based parsing loop. When encountering fields or keys not declared in the static Smithy interface definition, the parser invokes a utility path named skip_inner to skip past the unmapped elements and continue processing known fields.
The skipping implementation utilized a recursive parsing pattern to process nested arrays or object elements within the unrecognized keys. Because the implementation lacked nested limits, parsing complex structured data could cause uncontrolled recursion, identified as CWE-674. This design flaw allows remote attackers to exhaust the target program's stack allocation, forcing immediate crash states.
The root cause of CVE-2026-18140 resides in the recursive structure of the skip_inner helper in rust-runtime/aws-smithy-json/src/deserialize/token.rs. In standard execution, when the token stream yields Token::StartObject or Token::StartArray, the function recursively executes skip_inner with an incremented depth tracker. This behavior relies on recursive stack allocation to preserve state across elements of nested structures.
Each nested level in a JSON construct requires a distinct stack frame. A stack frame stores register states, function arguments, local variables, and the return address. When parsing structured input with deep arrays, the nesting structure forces the runtime to allocate stack frames proportional to the layout depth, creating an $O(N)$ stack dependency.
Unlike heap-allocated memory, thread stack limits are strictly bounded. On standard Linux environments, thread stacks range from 2MB to 8MB, and can be smaller in embedded systems or hyper-optimized microservices. When a payload exceeds the maximum stack size, a stack overflow occurs. In Rust, stack overflows bypass standard panic recovery blocks and immediately trigger a SIGSEGV signal, forcing the operating system to abort the server process.
The vulnerable implementation recursively executed skip_inner(depth + 1, tokens)? whenever it encountered start tokens for arrays or objects. Below is a code comparison showing how the patch resolved this pattern by converting the logic into an iterative loop that maintains a flat $O(1)$ stack space utilization.
// PRE-PATCH VULNERABLE RECURSION
fn skip_inner<'a>(
depth: isize,
tokens: &mut impl Iterator<Item = Result<Token<'a>, Error>>,
) -> Result<(), Error> {
loop {
match tokens.next().transpose()? {
Some(Token::StartObject { .. }) | Some(Token::StartArray { .. }) => {
// Recursing deepens stack consumption
skip_inner(depth + 1, tokens)?;
if depth == 0 { break; }
}
Some(Token::EndObject { .. }) | Some(Token::EndArray { .. }) => { break; }
_ => {}
}
}
Ok(())
}The remediation replaced the recursive logic with an iterative model tracking current depth in a single mutable variable within one execution frame. It introduces a fixed ceiling limit defined by MAX_SKIP_DEPTH to preemptively discard deeply nested objects before consuming excessive CPU cycles.
// POST-PATCH ITERATIVE FIX
const MAX_SKIP_DEPTH: usize = 512;
fn skip_inner<'a>(
initial_depth: usize,
tokens: &mut impl Iterator<Item = Result<Token<'a>, Error>>,
) -> Result<(), Error> {
let mut depth = initial_depth;
loop {
match tokens.next().transpose()? {
Some(Token::StartObject { .. }) | Some(Token::StartArray { .. }) => {
// Stack use remains flat while depth tracking is updated
depth = depth.checked_add(1).ok_or_else(|| {
Error::custom("exceeded max recursion depth")
})?;
if depth > MAX_SKIP_DEPTH {
return Err(Error::custom("exceeded max recursion depth"));
}
}
Some(Token::EndObject { .. }) | Some(Token::EndArray { .. }) => {
debug_assert!(depth > 0);
depth = depth.saturating_sub(1);
if depth == 0 { break; }
}
None => return Err(Error::custom("expected value")),
_ => {}
}
}
Ok(())
}This structural shift removes recursive execution altogether. By limiting parsing recursion to 512 levels, the memory footprint remains constrained, preventing any possibility of memory-exhaustion crashes regardless of incoming structure depth.
Exploitation of CVE-2026-18140 requires no authentication credentials or complex system preconditions. An attacker must locate any public-facing HTTP endpoint managed by a Smithy-rs service that accepts JSON request payloads. Because the deserializer processes payload formatting prior to mapping fields to application handlers, the exploit payload is evaluated as soon as parsing begins.
The attacker formats a JSON request containing an arbitrary, unmapped parameter key. The value mapped to this unrecognized key is structured as an extremely deep recursive array or object string, such as a sequence of nested brackets. This specific configuration forces the parsing engine to select the skip_inner logical branch.
{
"non_existent_key": [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[...]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
}When the deserializer parses this key, it processes each opening bracket. Under vulnerable builds, each bracket initiates a new stack frame, causing the stack pointer to overrun the guard page. The host operating system intercepts the invalid memory write, issues a SIGSEGV signal, and instantly terminates the service process.
The impact of exploiting CVE-2026-18140 is a complete denial of service across the targeted system. Because a stack overflow causes the entire operating system process to terminate instantly, active connection streams are forcefully closed without returning a standard error response. This bypasses typical internal recovery mechanics, ensuring that all client tasks on that host thread abort simultaneously.
The vulnerability presents zero threat of unauthorized privilege elevation, arbitrary memory manipulation, or sensitive data disclosure. The core threat vector centers on availability disruption. In multi-tenant environments or single-process architectures, a single malicious HTTP request can disrupt operations for all legitimate users connected to the host.
Due to the low complexity of constructing a payload and the lack of authentication requirements, the vulnerability presents a significant exploitation surface. This risk is reflected in the CVSS v3.1 score of 7.5, reflecting a network-exploitable, low-complexity denial-of-service vector.
Remediation of this vulnerability is achieved by upgrading the aws-smithy-json dependency to version 0.62.7 or newer. This update can be applied directly in Cargo environments by executing standard package upgrade procedures, which replaces the vulnerable recursive implementation with the corrected iterative logic.
If immediate recompilation and deployment are not viable, operational workarounds can minimize the exposure profile. Administrators should deploy Web Application Firewall (WAF) rule sets to analyze payload structures and block requests containing abnormally deep arrays or excessive sequential open-bracket sequences.
Additionally, configuring maximum request size thresholds at the reverse proxy or API gateway layers reduces risks. Restricting payloads to a low maximum threshold (e.g., under 100 KB) physically limits the quantity of open-bracket tokens that an attacker can insert into a payload, rendering stack exhaustion attacks impossible.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
aws-smithy-json Amazon | >= 0.32.0, <= 0.62.6 | 0.62.7 |
| Attribute | Detail |
|---|---|
| Vulnerability Type | Uncontrolled Recursion (CWE-674) |
| Impact | Denial of Service (Process Abort) |
| CVSS v3.1 Score | 7.5 (High) |
| EPSS Score | 0.00431 (Percentile: 35.02%) |
| Exploit Status | Proof of Concept Only |
| CISA KEV Status | Not Listed |
| Affected Components | rust-runtime/aws-smithy-json/src/deserialize/token.rs |
The software contains a function that can call itself recursively without a mechanism to limit the recursion depth, leading to excessive stack consumption.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.