Uncovering an Out of Memory Vulnerability in Gnark

How We Discovered CVE-2024-50354

Last month (october 2024), LambdaClass and Fuzzinglabs teams discovered an Out of Memory (OOM) vulnerability within the Gnark library, one of the most popular Go library for zk-SNARKS. During the deserialization of Verifying Keys, we can trigger a fatal error that can lead to DoS (Denial of Service). This discovery led to the assignment of CVE-2024-50354, and our collaboration with the Gnark team resulted in a fix quickly deployed on main version.

This post details our journey from uncovering this vulnerability to working alongside the Gnark developers to address it. We’ll explore the technical background, our analysis of the root cause, the solution implemented, and the broader significance of addressing such flaws in cryptographic libraries.

Introduction: What is Zero-Knowledge Proof (ZKP)?

A Zero-Knowledge Proof (ZKP) is a cryptographic technique that allows one party, the prover, to demonstrate knowledge of specific information (like a secret key) to another party, the verifier, without revealing the information itself.

How ZKPs Work:

  • The prover demonstrates knowledge without actually revealing it.
  • The verifier becomes convinced of the prover’s knowledge but learns nothing about the actual data.

A Zero-Knowledge Proof (ZKP) allows someone to prove they know a solution without revealing it. This technology enables private transactions, secure authentication, and confidential voting by ensuring privacy and trust.

What are ZK-SNARKs?

SNARKs (Succinct Non-Interactive Arguments of Knowledge) are a type of ZKP that provide both succinctness and non-interactiveness:

  1. Succinctness: The proofs are extremely compact and quick to verify, conserving storage and enhancing scalability.
  2. Non-Interactivity: Only a single exchange is needed between prover and verifier, making the process faster and simpler.

Now, Enter Gnark and the Issue: Out of Memory Error on Verifying Key Deserialization

In ZK-SNARK systems, two essential keys handle the verification process:

  1. Proving Key: A complex set of values, including elliptic curve points, that allows the prover to demonstrate the satisfiability of a circuit.
  2. Verifying Key: A corresponding set of values for the verifier to confirm the proof’s validity.

When deserializing the Verifying Key in the Gnark library, we found an Out of Memory (OOM) vulnerability. This issue arises if the program attempts an excessive memory allocation, leading to crashes. The flaw particularly affected applications using the Groth16 proving scheme and was also possible with Proving Keys.

How We Found the Issue

During testing, we observed abnormal memory usage when loading a Verifying Key. This memory surge was due to an incorrect number of commitments (sometimes millions) being read from the serialized file. The original implementation allocated a list based on file data, potentially causing excessive memory allocations. In one instance, the list allocation for commitments, intended for only a few elements, attempted to create billions, which quickly overwhelmed the system.

Example code snippet triggering the error:

Root Cause Analysis

The vulnerability stemmed from the ReadFrom function in marshal.go, within the bn254 elliptic curve implementation in Gnark, however, this vulnerability appears for all elliptic curves implemented in gnark, not only bn254. When reading a Verifying Key, this function extracted the nbCommitments value directly from the deserialized file. In our test file, nbCommitments was a staggering 2,327,186,600, leading to memory allocations around ±1 TB – well beyond typical system limits.

The resulting error output highlighted an unrecoverable memory state:

Root Cause Analysis

To address the issue, the Gnark developers implemented a safer, iterative approach for deserializing Verifying Keys. Here’s a summary of the fix:

  1. Dynamic List Building: Instead of creating a list with a predetermined size, they initialized an empty list and populated it iteratively.
  2. Element-by-Element Validation: Each key is deserialized one at a time, ensuring memory is only allocated as needed.
  3. Double-Check Length: A final check verifies that the list size matches nbCommitments before continuing.

By deserializing keys one by one and validating at each step, Gnark avoids the OOM vulnerability, enhancing stability and resilience.

This fix ensures the inability to compromise the availability of the service, one of the four foundational principles of cybersecurity.

Final Thoughts

This experience highlights the importance of efficient memory management in cryptographic libraries, where even minor flaws can have significant security implications. Addressing this vulnerability in Gnark contributes to the security of ZK-SNARK implementations, enabling reliable, resource-conscious cryptographic applications.

Our work with the Gnark developers exemplifies the collaborative spirit needed to strengthen the cryptographic ecosystem.

Patrick Ventuzelo / @Pat_Ventuzelo

About Us

Founded in 2021 and headquartered in Paris, FuzzingLabs is a cybersecurity startup specializing in vulnerability research, fuzzing, and blockchain security. We combine cutting-edge research with hands-on expertise to secure some of the most critical components in the blockchain ecosystem.

Contact us for an audit or long term partnership!

Get Your Free Security Quote!

Let’s work together to ensure your peace of mind.

Keep in touch with us !

email

contact@fuzzinglabs.com

X (Twitter)

@FuzzingLabs

Github

FuzzingLabs

LinkedIn

FuzzingLabs

email

contact@fuzzinglabs.com

X (Twitter)

@FuzzingLabs

Github

FuzzingLabs

LinkedIn

FuzzingLabs