Chainlink VRF V2 Audit
Smart Contract Security Assessment
30.09.2021
SUMMARY
ABSTRACT
Dedaub was commissioned to perform a security audit on the 2nd version of the VRF smart contracts, on branch “develop” of https://github.com/smartcontractkit/chainlink at commit hash 7547b562579b4f201994fd85fb50d799ae1d918a. Two senior auditors worked over the codebase over one week. The audit examined the contracts:
- contracts/src/v0.8/dev/VRFConsumerBaseV2.sol
- contracts/src/v0.8/dev/VRF.sol
- This contract was mostly inspected as a diff from the v1 (v0.6/VRF.sol) to v2 (v0.8/dev/VRF.sol) and the cryptographic operations were mostly considered trusted since this code has been well-audited and tested before
- contracts/src/v0.8/dev/VRFCoordinatorV2.sol
- any other functionality highly related with these contracts, but without exhaustive inspection. Specifically, the offchain operations written in vrf_coordinator_v2.go.
SETTING & CAVEATS
The exhaustively audited code base is of small size, at around 1KLoC, but with extensive interactions and protocol-level complexity. The code and accompanying artifacts (e.g., test suite, documentation) are of excellent quality, developed with high professional standards.
We emphasized protocol-level considerations, in addition to code review. The items below can be considered context notes, possibly to inform future design, or documentation for the benefit of external users.
-
It may not be clear to users what Verified Random Functions truly verify and, consequently, what are the threats. We find statements concerning guarantees even if a Chainlink oracle (“node”) is compromised to be hard to interpret correctly. E.g., the following in the past Chainlink VRF documentation:
- The proof is published and verified on-chain before it can be used by any consuming applications. This process ensures that the results cannot be tampered with nor manipulated by anyone, including oracle operators, miners, users and even smart contract developers.
[https://docs.chain.link/docs/chainlink-vrf/] - The fundamental benefit of using Chainlink VRF is its verifiable randomness. Even if a node is compromised, it cannot manipulate and/or supply biased answers — the on-chain cryptographic proof would fail. The worst case scenario is that the compromised node does not return a response to a request[...] Even in the unlikely scenario that a node is compromised, its resulting randomness cannot be manipulated.
[https://blog.chain.link/chainlink-vrf-on-chain-verifiable-randomness/]
What the above seems to imply is not accurate. If a Chainlink node’s VRF secret key is compromised, the VRF becomes a mere deterministic pseudo-random generator. Its randomness is then, at best, on-chain randomness, which has well-known issues. Certainly, the collusion of a miner and an oracle operator can open the door to attacks.
- The proof is published and verified on-chain before it can be used by any consuming applications. This process ensures that the results cannot be tampered with nor manipulated by anyone, including oracle operators, miners, users and even smart contract developers.
-
The current design does not accept a seed from the user of the VRF functionality. This is ideal for the usual case, but it is limiting for highly sophisticated clients. Specifically, the typical client contract only has access to on-chain information. In this case, accepting a seed from the client is pointless: the current approach of the VRF functionality both gets the most obtainable in terms of on-chain randomness (by taking the blockhash of a block not mined at the time of the request) and would destroy any seed provided by the caller in the process. However, a more advanced API can be envisioned (perhaps in addition to the current one) that allows the caller to supply their own randomness in the form of a seed. (Such a seed should not then be hashed with a blockhash, or a miner can bias the outcome.) This approach permits, for instance, the use of two separate off-chain randomness sources. If the VRF oracle accepts randomness from the user (in addition to employing its own secret key) the result is a better randomness guarantee: biasing the random outcome would require compromising both randomness sources (i.e., both the secret key of the Chainlink VRF oracle, and the other source of randomness).
VULNERABILITIES & FUNCTIONAL ISSUES
This section details issues affecting the functionality of the contract. Dedaub generally categorizes issues according to the following severities, but may also take other considerations into account such as impact or difficulty in exploitation:
- User or system funds can be lost when third-party systems misbehave.
- DoS, under specific conditions.
- Part of the functionality becomes unusable due to a programming error.
- Breaking important system invariants but without apparent consequences.
- Buggy functionality for trusted users where a workaround exists.
- Security issues which may manifest when the system evolves.
Issue resolution includes “dismissed” or “acknowledged” but no action taken, by the client, or “resolved”, per the auditors.