Audit Teardown
This article illustrates the main sections of an audit report, using examples from recent audits we have conducted for clients.
When detailing vulnerabilities found by code inspection I have shown the approach used, or thinking behind the way that they were found.
A typical report will contain the following sections :
- background — scope / dates / client
- summary of business logic
- methodology — code inspection and tools
- executive summaries
- issues
- tools used and results from them
Issues Found
We’ll go out of order, starting with the issues, this section is the heart of the audit report where we list all the potential vulnerabilities that we have found.
Each issue will be reported in a standard format :
- Title and risk categorisation
- Location in the code
- Description and code snippet
- Recommendations
- Status
Let’s have a look at some issues from recent audits :
Unbounded call in ‘setConfiguration‘ can exceed the block gas limit
Risk : LOW
Location : Utils.sol#62
The function setConfiguration() is used to set up a status for a number of addresses.
The function accepts a dynamic array of addresses and a dynamic array of bytes32 statuses. The gas costs for the unbounded loop in this call risks exceeding the block gas limit.
function setConfiguration( address[] memory addresses,bytes32[] memory status,
bool hasStatus ) external onlyOwner {
if (addresses.length != status.length) revert InvalidConfig);
uint256 length = status.length;
for (uint256 i; i < length; ) {
setStatus(addresses[i], status[i], hasStatus);
unchecked {
++i;
}
}
}
}
How did we find this ?
Unbounded loops are a well known vulnerability, so it makes sense to check all the loops in a contract
Swap Execution and Slippage Control in removeSurplus
Risk Low
Location Treasury.sol#57
The removeSurplus function in Treasury is designed to convert excess treasury ETH to ABC tokens.
However, its current implementation might allow for market manipulation, particularly if large amounts of ETH are involved. Specifically, the function’s reliance on a single liquidity pool and the fixed slippage parameter (acceptableSlippage) could be exploited.
An attacker could use a flash loan to temporarily manipulate the price of ABC in the liquidity pool, triggering removeSurplus to swap ETH for ABC at an inflated rate.
After the swap, the attacker could sell the acquired ABC tokens at a higher rate in other transactions within the same block, and then repay the flash loan.
Recommendation
- Implement dynamic slippage control based on current market conditions.
- Introduce a time-weighted average price (TWAP) mechanism to determine the swap rate, reducing vulnerability to short-term price manipulation.
- Split large swaps into multiple smaller transactions to minimise market impact.
- Utilise external price oracles for additional price verification.
- Implement circuit breakers that pause swapping in case of detected abnormal activities, such as sudden large price movements.
Status
Resolved, with the addition of access control and mitigation against flash loans.
This issue is an economic attack. Manipulating prices is a common exploit, and flash loans can be used to increase the effect.
How can you spot issues like this ?
- Adopt an attackers mindset
- Look for ways that a price can be manipulated, in particular look at whether there is protection against slippage and flash loans.
The next two issues relate to controlling access to configuration changing functions, they illustrate two sides of the problem :
Missing modifier
Risk High
Affects Fees.sol
The function withdrawFees is missing a modifier allowing anyone to withdraw fees.
function withdrawFees(uint8 _node, uint8 month) {
...
}
Recommendation
Use the existing `onlyOwner` modifier to guard this function
Status
Resolved.
Critical addresses cannot be updated
Risk Low
Affects Treasury.sol
In the constructor the following addresses are set:
nft = NFT721(_nftAddress);
quoteErc20 = IERC20(_quoteErc20Address);
priceFeed = AggregatorV3Interface(_priceFeedAddress);
However no setter functions exist for changing these variables.
Therefore, the contract may become unusable should control of these addresses be lost.
Recommendation
Add functions to allow the addresses to be changed.
Status
Resolved.
How did we find these ?
It is vital when auditing a contract to have a clear idea of the privileged addresses used in the project.
These addresses may relate to
- privileged roles able to perform administratrive functions
- controllers of wallets, vaults or fund holding contracts.
Given that most attacks aim to steal funds, this area will be a prime target for attackers.
You need to check therefore that
- Access control using these addresses is correct and complete
- Functions used to change such configuration need to be absolutely secure.
On the other hand, we need to ensure that the security around configuration isn’t too brittle, it should be flexible enough to allow for the situation where, for example a private key being lost or compromised.
A good general solution is the use of multisigs, a standard solution is Gnosis Safe wallet.
Tickets may be processed out of order
Risk Medium
Location Ticket.sol
In process tickets function, there is no check to ensure that tickets are only processed for completed rounds and that rounds cannot be skipped
function processTickets(uint16 round) external onlyOwner() {
…
}
Recommendation
Use a monotic variable to track the last completed round, and only allow one round greater than that to be processed at a time.
Status
Resolved.
Tickets or loans of zero value may be purchased
Risk Medium
Location — multiple contracts
In multiple projects we have seen the assumption (which makes business sense) that users would not try to take out a loan, or buy a ticket having zero value.
This assumption has meant that there have been inadequate checks on input data, specifically not checking for zero value tickets / loans.
Such transactions could lead to compromised state iin the contract, or a denial of service attack.
Recommendation
Always check that input data is in a sensible range, beware of assumptions that have been made about user behaviour.
Status
Resolved.
Other sections
Executive Summary
The report requires a summary of the issues found, there may be a technical and a non technical summary to address the different audiences.
Background — scope / dates / client
The report usually starts with some background, establishing the timescale and scope of the report
Extropy was contracted by client ABC to conduct a code review and vulnerability assessment of the project. The review was carried out between 15th and 21st June.
Scope
The following contracts were audited:
Lottery.sol
Ticket.sol
User.sol
Utils.sol
The following contracts / files were out of scope:
TokenDistribution.sol
Marketplace.sol
System Overview
It is useful to include a description of the functionality of the project
The protocol allow users to play a game:…
Each round a winning combination will be generated …
Data Structures
Not only does this give the readers of the report an understanding of the project, it also shows the development team, the assumptions that the auditors have, which if incomplete can be addressed by the developers.
Methodology
There should be a section outlining the methodology used for the audit :
The risk rating given for issues follows the standard approach of the OWASP Foundation. We combine
two factors :Likelihood of exploit
Impact of Exploit
The Categories we use are Critical, High, Medium, Low and Informational These categories may notalign with the categories used by other companies.
The informational category is used to contain suggestions for optimisation (where this is not seen as causing significant impact), or for alternative design or best practices.
Executive Summary
The report requires a summary of the issues found, there may be a technical and a non technical summary to address different audiences.
Where to go from here ?
For further examples of audit reports, visit our website :
If you have a project that is ready to deploy, visit
Audit Proposal
to get an audit quote,
and if you mention this article you get a discount.
If you would like to expand your auditing skills, we run auditing courses, targeting EVM, Starknet and Mina.
You can find details of the upcoming courses on our education site :
Extropy Education