Breakdown of 100 security audits: Key insights from 1605 vulnerability findings

Veridise
Veridise
Published in
9 min read2 days ago

Over $10 billion has been hacked from various blockchain and DeFi platforms since 2018. A significant part of this number stems from security vulnerabilities in smart contracts. Yet today, the industry still has limited visibility into which types of vulnerabilities contribute to these numbers.

At Veridise, we decided to contribute our analysis by examining our 100 most recent security audits from our issues database. After a few days of running spreadsheets, we’ve arrived at some insightful graphs.

So, if you’re a developer or co-founder of a web3 protocol, you might find these charts useful when approaching an internal security review of your codebase. This can give you the opportunity to direct your attention to the types of bugs that result in the most severe vulnerabilities.

Summary of 100 audits and 1605 vulnerability issues:

We’ve analyzed 100 audit projects from our audit database. This covered a wide range of smart contracts, blockchain implementations, and zero-knowledge solutions. In total, the data set included 1605 issues, and out of the issues, 1533 had identified issue types.

TLDR Summary:

  • Our security audit contain an average of 16.1 issues, ZK audits have slightly more issues (18.0) than other audits.
  • However, Zero-Knowledge audits have a 2x higher chance of having critical issue compared to the rest of the audits.
  • Among all audits, the most common type of bug is Logic error. The bug type with the highest number of severe issues is also Logic error. 41% of severe (critical or high) issue types are Logic errors.
  • 78% of high-severity issues across all audits trace to just 5 issue types: Logic Error, Data Validation, Underconstrained Circuit, Denial of Service and Access Control.

Our security audit contains 16.1 issues on average

As we can see from the statistics below, our audits contain approximately 16.1 issues on average.

If we exclude “info” and “warning” categories, the number drops to around half.

Interestingly, our ZK audits tend to have more bugs than rest of the audits.

Highest severity bugs are specific to your project

Let’s examine a chart that categorizes all Critical and High severity issues by type, focusing on the Top-20 issue types:

As we can see, Logic Errors dominate the chart, suggesting that the highest severity bugs are specific to your project. Logic Errors include flawed if/else statements, loop errors, incorrect assumptions, and other similar mistakes.

Looking more broadly, just four types of issues account for 78% of all detected Critical or High issues:

  • Logic Errors
  • Data Validation
  • Underconstrained Circuit
  • Denial of Service
  • Access Control

That is 174 issues out of 223 severe (critical or high) issues in total.

Later in the article, we’ll introduce these top-5 issue types in more detail and provide brief suggestions on how to spot this particular type of bug.

Before that, let’s zoom out a bit to examine all 1605 issues.

A chart breaking down issues types across all severity levels.

In the chart above, we focused only on Critical/High severity issues.

Now, let’s examine all 1605 issues across every severity levels:

  • Critical
  • High
  • Medium
  • Low
  • Warning
  • Info

Amount of issues per type:

When considering all issues across all severity levels, the top three categories are:

  • Logic errors
  • Maintainability issue
  • Data validation

Note on “Maintainability issues”:

Maintainability issues are not strictly security vulnerabilities. They can include, for example, poor coding practices. However, as one of our lead auditors described, these issues are sometimes “one epsilon away from turning into Critical bugs.”

We document these to help our clients not just in bug detection, but in proactively preventing potential vulnerabilities.

Next — let’s connect the two charts together

So, among all the issues we’ve found, what portion of them are Critical/High in severity?

The chart below shows exactly this.

The blue color represents data from the blue chart above, and red from the red chart above.

Depending on the issue type, Critical/High severity bugs comprise roughly 10–30% of all issues of a particular type.

Nearly all issue types contain notable part of Critical/High vulnerabilities.

“Maintainability” hardly contains any Critical/High severity issues. As described before, these are pointing out best practices to avoid high severity vulnerabilities occurring in potential later edits of the code.

However, there are outliers that the chart above doesn’t fully capture. Let’s create a new chart.

Percentage of Critical/High severity bugs per issue type

Let’s use percentages instead of absolute numbers to discover something really interesting.

The red part of the bar describes the percentage of Critical and High severity bugs in each issue category.

This is indeed revealing. Underconstrained Circuits historically have 90% likelihood of containing Critical or High issue. (89.4% to be really precise)

Because of this finding, let’s take a detour to examine ZK security and Underconstrained Circuits in more detail.

90% of “Underconstrained Circuits” issues are severe

Let’s focus on the first row of the chart: Underconstrained Circuit. 90% of Underconstained Circuit issues throughout all Veridise ZK audits have been marked as Critical or High in severity.

Underconstrained Circuits are typical issues specifically in zero-knowledge related audits. They do not occur in traditional smart contracts.

In Veridise audits, zero-knowledge tech has often been used in key infrastructure protocols, such as in L2 zk-Rollups, ZK-VMs, or, for example, in Circom libraries (where we’ve spotted a significant bug earlier)

The security of these infrastructure protocols affects all dapps built on top of them, underlining the importance of ZK security.

So, what exactly are “Underconstrained Circuits”?

An “underconstrained circuit” security vulnerability occurs when the constraints of an arithmetic circuit do not sufficiently enforce all necessary conditions to check that some computation was performed correctly. In most cases, this means that the constraints do not enforce that the computation is deterministic.

This vulnerability can lead to situations where an alternate witness generator program could provide an unexpected or malicious assignment to circuit’s signals. Essentially, a malicious party could generate a proof that deceives the verifier into accepting an incorrect statement as true.

In other words, undercontrained circuit happens when verifier’s constraints are too lax allowing the user to violate implicit constraints that were not enforced.

This can seriously undermine the integrity of the protocol.

Now, let’s zoom out a bit, and take a detour and bird eye’s view on ZK security compared to other audits.

ZK audits have 2 times the likelihood of having critical issues compared to the rest of our audits

It turns out ZK security is simply more challenging. This is understandable given the complexity and rapid development of ZK technology.

Moreover, zero-knowledge security is challenging and virtually impossible without specialized tools. Only a handful of security auditors have professional-level capabilities to audit ZK circuits.

ZK is precisely the area where we at Veridise have doubled down and invested in specialized in-house tools that enable us to uncover vulnerabilities that would otherwise go unnoticed. Picus is one of our ZK tools, and an open-source version is also available on our Github.

Let’s end the ZK detour here and return to examining the other most common Critical/High issue types.

Top-5 of Critical/High vulnerability types explained

Let’s get back to our first graph and examine the issue types with the most amount of Critical/High issues.

We’ll provide a brief explanation of the issue and suggestions on how your can find this particular type of bug.

1. Logic Error

Logic errors occur when the code does not perform its intended functionality due to a mistake in the logical flow. These errors can lead to unintended behavior, which might compromise the security or functionality of the application. A typical example is a smart contract that mistakenly allows users to withdraw funds in excess of their balance.

At Veridise, we’ve observed that logic errors often result from a misalignment between the developer’s understanding and the actual implementation of business logic. Our audits frequently uncover instances where boundary conditions are not properly handled, leading to critical security flaws.

What can I do to avoid Logic Error bugs? To prevent logic errors, thorough testing is crucial so aim for the highest test coverage possible. Additionally, you can consider peer reviews within your team.

2. Data Validation

Data validation in smart contracts involves checking inputs against expected criteria to prevent errors and vulnerabilities. It ensures input values match the expected behavior. A subset of these issues include arithmetic safety checks and input sanitization to guard against issues such as overflow, underflow, and injection attacks. Smart contracts use preconditions and assertions to verify state and input validity before executing logic.

What can I do to avoid Data Validation bugs? Utilize negative testing to test against potentially malicious inputs. Also, ensure robust input validation by employing libraries specifically designed for data sanitization and validation, such as OpenZeppelin’s contracts for Ethereum-based applications. Regularly update these libraries to incorporate the latest security practices and patches.

3. Underconstrained Circuit

An “underconstrained circuit” security vulnerability occurs when an arithmetic circuit that defines a computation does not fully enforce all the necessary constraints to ensure its correctness.

This can lead to situations where a malicious party can generate a proof that deceives the verifier into accepting an incorrect statement as true, potentially compromising the integrity of the cryptographic protocol.

What can I do to avoid Underconstrained Circuit issues? Ensure all constraints are properly defined and enforced. In particular, if the witness generator is deterministic then their constraints should ensure all signals are assigned deterministic values. Optimizations can be performed such that non-output signals do not need to be assigned deterministic values but they must be very carefully considered to ensure there are no side-effects. You can use tools like Picus developed by Veridise to help prevent unconstrained circuits.

4. Denial of Service

Denial of Service can occur when resources become overloaded or excessively costly, preventing legitimate operations. For example, smart contracts might be designed in a way that allows an attacker to consume all available gas.

What can I do to avoid Denial of Service bugs? Optimize contract functions to minimize their gas usage and prevent loops from consuming excessive gas. Tools like Gas Station Network (GSN) can help identify functions that might become gas-heavy under certain conditions. Implement rate limiting and proper exception handling to mitigate potential DoS attacks. Also, be aware of who can consume gas, a common attack involves users reverting in their fallback or consuming all forwarded gas.

5. Access Control

Access control in smart contracts refers to mechanisms that restrict who can interact with certain functions or data within the contract. It typically involves defining roles or permissions that are checked before executing sensitive operations, such as modifying critical state variables or transferring assets. Smart contracts use modifiers or require statements to enforce these rules, ensuring that only authorized addresses can trigger specific functionalities.

What can I do to avoid Access Control bugs? Use established smart contract libraries (such as Ownable and Roles in Ethereum) which provide well-tested access control mechanisms such as role-based permissions. Regularly audit your access control lists and configurations to ensure they align with current security standards and business requirements. Negative testing is also important, as is clearly documenting the actors who will be interacting with your protocol and what they should be able to do.

Summary and further reading

Best security comes from high testing coverage combined with professional level audits. Not with either one alone.

Before conducting external security audit, there are many steps you can take to improve your security practices. We’ve provided a brief suggestions above, and also written a separate article on the topic:

Prep guide: 7 essential tips to prepare for blockchain security audit

We hope these insights are helpful when you focus on the security practices of your developer team before conducting external security audit.

Thank you for reading.

Article author: Mikko Ikola, Head of Marketing at Veridise

Thank you Jon Stephens, Isil Dillig, Mark Anthony, Ben Sepanski and Kostas Ferles for reviewing the blog post.

Want to learn more about Veridise?

Twitter | Lens | LinkedIn | Github | Request Audit

--

--

Veridise
Veridise

Hardening blockchain security with formal methods. We write about blockchain & zero-knowledge proof security. Contact us for industry-leading security audits.