Burak Benligiray
Published in
6 min readDec 15, 2023


AccessControlRegistry Contract Vulnerability Related to OpenZeppelin Dependencies

See the API3 security announcement published on December 10th, 2023 for context.

The vulnerability disclosed in this article has been eliminated without ever being exploited, and no user was harmed.

On December 6th, Quantstamp informed us that a contract that they have previously audited for API3 was potentially affected by a vulnerability. They refrained from providing more details as the vulnerability applies to contract implementations by other parties as well, but they offered to guide us through a response to it. We informed them that the said contract is not in use yet and no response is required. However, we requested from them to check our AccessControlRegistry implementation for the same vulnerability, as it shared similarities. Our suspicion was confirmed and we addressed the issue across many chains within a few hours, followed by a migration, which ultimately resulted in the elimination of the vulnerability without any loss of funds. We thank Quantstamp for the warning and our users for their swift response.

This report is a full disclosure of the specific vulnerability. As disclosed by OpenZeppelin on December 8th, inheriting two components from the OpenZeppelin contracts, ERC2771Context and Multicall, resulted in anyone being able to spoof sender addresses in the inheriting contract. This was patched in v4.9.4, v4.9.5 and v5.0.1, soon after their disclosure. Our AccessControlRegistry implementation was one of the contracts that was affected by this issue.

What is AccessControlRegistry?

AccessControlRegistry is a common-use access control implementation, similar in purpose to AccessManager. This kind of a design is preferable because it keeps a record of all delegated on-chain privileges in a single place, enabling them to be inspected by anyone with ease.

Iterations of AccessControlRegistry have been audited by Sigma Prime in December 2021, Trail of Bits in March 2023, and finally, Sigma Prime again in the same month of March 2023 (after which the code was frozen). The multicall functionality was added after the first audit, and the ERC2771Context implementation was inherited after the second audit, which means the vulnerability existed in the commit that was reviewed in the last audit, but was not detected.

Which users were vulnerable?

AccessControlRegistry is not related to many of our widely used contracts, which include:

  • The API3 token contract
  • The API3 DAO and staking pool contracts
  • The Airnode request-response protocol (RRP) contracts, which Airnode interacts with to detect requests and fulfill them. (Therefore, users of Airnode, ChainAPI, or QRNG were not affected by this vulnerability.)

However, AccessControlRegistry was used by Api3ServerV1, which is the contract that API3 uses to serve data feeds. A user can read a data feed served over Api3ServerV1 in two ways:

  1. By specifying a “data feed ID”, which is the hash of all parameters of the data feed. You can think of the data feed ID as the IP address of the data feed.
  2. By specifying a “dAPI name”, which is pointed to a data feed ID by any of the “dAPI name setters” of Api3ServerV1 (typically a multisig or a contract with a very restrictive rule set). You can think of the dAPI name as the domain name of the data feed.

dAPI names are useful, as they allow API3 to continuously curate data feed compositions, i.e., the number and selection of the underlying API providers, without requiring any action from the user. On the other hand, a user that reads data feeds by IDs would have to execute any necessary composition update themselves, e.g., if an API provider ended service, the user would have to update their data feed ID in a way that specifies a replacement, which is too involved for the liking of most data feed users.

Api3ServerV1 offloads the implementation of checking or updating if an account is a dAPI name setter to AccessControlRegistry. Therefore, the suspected attack would have happened as follows:

  • The attacker calls AccessControlRegistry, spoofing the Api3ServerV1 “manager” (which is currently a 4-of-8 multisig owned by technical domain experts at API3) address to grant themselves the dAPI name setter role.
  • The attacker updates a data feed of their own on Api3ServerV1 with an arbitrary value.
  • The attacker points a dAPI name to the ID of their own data feed.
  • The attacker steals funds from a contract that depends on the correct operation of the dAPI to secure funds.

As a note, these four steps could have been executed in a single transaction.

The API3 Market and the API3 documentation recommend the user to read data feeds through a DapiProxy contract, which uses the dAPI name to identify the data feed to be used. Therefore, all users that were reading a data feed through a DapiProxy contract were vulnerable to this attack. Users that were reading their data feed through a DataFeedProxy contract, which uses the data feed ID to identify the data feed to be used, were not vulnerable. For example, Nodary has been recommending its users to use DataFeedProxy, acknowledging that it’s a more trust-minimized method of reading its feeds (assuming that the user has committed to reading single-source Nodary feeds to begin with).

The timeline

Dec 6, 1:00PM (all times in GMT): Quantstamp informed us that a contract that they have previously audited for API3 was potentially affected by a vulnerability. We requested from them to check our AccessControlRegistry implementation for the same vulnerability. The fact that Quantstamp agreed to do so confirmed our suspicion that this was related to OpenZeppelin’s ERC2771Context contract, and we immediately started working on an AccessControlRegistry implementation that excluded that dependency.

Dec 6, 3:30PM: The new AccessControlRegistry implementation and all the immutably dependent contracts (Api3ServerV1, ProxyFactory) were deployed on all the chains that the known dAPI users were on, which were Gnosis Chain, Kava Chain, Linea, Mantle, Moonbeam, Polygon PoS, and Polygon zkEVM.

Dec 6, 5:00PM: Quantstamp provided us with screenshots that implied that they were able to produce a POC that allowed them to call a role management function with a spoofed address in AccessControlRegistry, and confirmed that removing the ERC2771Context inheritance would be a way to fix the issue conclusively.

Dec 6, 6:00PM: The new dAPIs to be switched to by the known users were operational on all respective chains, the dAPI names for these were all set by the manager multisig, and the new DapiProxy contracts pointing to these dAPIs were all deployed.

Dec 6, 7:00PM: After an internal review of the new proxies, we reached out to the known dAPI users to replace their old proxy addresses with the new ones.

Dec 8, 0:00AM: OpenZeppelin disclosed the vulnerability in detail.

Dec 10, 5:00PM: Having confirmed that all known dAPI users have switched to the new proxies and the API3 Market was fully operational with the new contract deployments on all supported chains, we published a security announcement, urging any users that we may not know of to use the API3 Market to deploy a new proxy and switch to it immediately.

Dec 15, 9:00AM: We stopped updating the old Api3ServerV1 contract as stated in the security announcement.

API3 prioritizes user security first and foremost, and security without transparency is only a promise. We have pioneered API provider-centric oracle solutions, which are superior because they enable a data supply chain whose security can be audited by its users. In a similar way, we take great care in disclosing security incidents in detail, including the ones that would not have been noticed otherwise.

As we have mentioned, the disclosed vulnerability has been eliminated, and we have no reason to be any less confident in our contract implementations than we were before. Nevertheless, as a best practice, we will conduct a re-audit of all the related contracts, and publish the resulting report in the respective Github repository as usual.