Feb 15, 2026·6 min read·29 visits
Triton VM failed to include the FRI polynomial and trace height in the transcript hash. This broke the Fiat-Shamir binding, allowing attackers to retroactively choose values that satisfy the verifier's challenges, effectively forging proofs for invalid computations.
A critical soundness vulnerability in Triton VM allows attackers to forge Zero-Knowledge proofs by exploiting a flaw in the Fiat-Shamir transform implementation. By failing to absorb specific polynomial coefficients into the cryptographic sponge before generating challenges, the verifier allows a malicious prover to craft the proof after seeing the 'random' challenges.
Zero-Knowledge Virtual Machines (ZK-VMs) are the alchemy of modern cryptography. They promise to let you run a program, produce a tiny cryptographic receipt (the proof), and convince anyone that the computation was correct without revealing the inputs. It's magic, but magic relies on strict rules. In the world of STARKs (Scalable Transparent Arguments of Knowledge), the most sacred rule is Fiat-Shamir.
Imagine a magician (the Prover) asking a volunteer (the Verifier) to pick a card. If the magician forces the volunteer to pick the Ace of Spades, it's not a trick; it's a scam. In non-interactive ZK proofs, we replace the volunteer with a cryptographic hash function (a 'random oracle' or 'sponge'). The Prover dumps their work into the sponge, and the sponge squeezes out random challenges. Because the challenges depend on the work, the Prover can't predict them.
Triton VM, a Rust-based ZK-VM, built a sophisticated sponge using the Tip5 hash function. But in version < 2.0.0, the sponge had a little case of selective amnesia. It forgot to look at the Prover's final homework before handing out the grade. And as any cheater knows, if the teacher hands you the answer key before you turn in the test, you're going to get an A+.
The vulnerability lies deep within the FRI (Fast Reed-Solomon Interactive Oracle Proof of Proximity) protocol implementation. FRI is the heavy lifting engine that proves a polynomial has a low degree. In a proper implementation, every single coefficient and commitment sent by the Prover must be absorbed into the transcript (the sponge state) before the Verifier generates the next challenge.
Triton VM uses a macro called proof_items! to define what gets absorbed. In the vulnerable versions, two critical items were explicitly set to exclude themselves from the sponge:
FriPolynomial: The coefficients of the final polynomial.Log2PaddedHeight: The size of the execution trace.Because these values were not absorbed, the random challenges generated by the sponge did not depend on them. This creates a causality loop break. The Prover can compute the challenges first, and then choose a FriPolynomial that happens to satisfy those specific challenges. It effectively turns the system from "I promise this polynomial is valid" to "I found a polynomial that matches the 3 random points you just asked about."
The fix is embarrassingly simple, which highlights just how fragile ZK implementations can be. The vulnerability wasn't a buffer overflow or a complex logic error; it was a configuration flag in a Rust macro.
In triton-vm/src/proof_item.rs, the proof_items! macro defines how different parts of the proof interact with the Fiat-Shamir sponge. Look at the diff below. The boolean value indicates whether the item is included in the Fiat-Shamir heuristic (hashed).
Vulnerable Code:
// The 'false' here means: "Don't add this to the hash state"
Log2PaddedHeight(u32) => false, try_into_log2_padded_height,
FriPolynomial(Polynomial<'static, XFieldElement>) => false, try_into_fri_polynomial,Patched Code (Commit 3a045d636...):
// The 'true' binds the prover to these values BEFORE challenges are issued
Log2PaddedHeight(u32) => true, try_into_log2_padded_height,
FriPolynomial(Polynomial<'static, XFieldElement>) => true, try_into_fri_polynomial,By flipping false to true, the developers ensured that these values alter the sponge state. If a malicious prover tries to change the polynomial later, the sponge state would be different, resulting in different challenges, invalidating their forged solution.
To exploit this, we don't need to break encryption. We just need to abuse the order of operations. Here is how a malicious Prover forges a proof for an invalid state transition (e.g., minting 1,000,000 tokens out of thin air):
FriPolynomial.FriPolynomial isn't hashed, the sponge state depends only on previous items. We can locally calculate exactly what indices (challenges) the verifier will query.true.This is a soundness error. In ZK terms, soundness is the guarantee that false statements cannot be proven. With this vulnerability, that guarantee evaporates. If Triton VM is used as the validity proof for a blockchain rollup, an attacker could submit a proof that validates an invalid block—stealing funds, corrupting state, or censoring transactions.
Because the exploit is algorithmic, it is 100% reliable. There is no race condition, no heap grooming, and no luck involved. If you are running a version prior to 2.0.0, any proof you verify is essentially worthless against a sophisticated adversary. The severity is effectively maximum for the context of a ZK system.
The Triton VM team released version 2.0.0 to address this. The patch not only flips the inclusion flags to true but also increments the protocol version number, effectively invalidating all old proofs (since they were generated with a broken Fiat-Shamir transform).
If you are using triton-vm, update your Cargo.toml immediately:
[dependencies]
triton-vm = "2.0.0"Additionally, the patch introduced sanity checks for log2_padded_height to prevent integer overflows, closing the door on a potential Denial of Service vector where a prover could claim an impossibly large execution trace.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Triton VM TritonVM | < 2.0.0 | 2.0.0 |
| Attribute | Detail |
|---|---|
| CWE | CWE-345: Insufficient Verification of Data Authenticity |
| Attack Vector | Network (Proof Submission) |
| Impact | Proof Forgery / Integrity Compromise |
| CVSS v3.1 | 9.8 (Critical) |
| Affected Component | Fiat-Shamir Transform (FRI Protocol) |
| Patch Commit | 3a045d636e97bb2eb628671db0001aa665c19dd8 |
An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.
A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.
OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.
An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.
A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.
An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.