Quadrata security record

Ethereumquadrata.com

As of 3 Nov 2026, Quadrata has 3 audit reports by 2 security firms on Trustblock; the latest is by CertiK, dated 3 Jul 2023. Those reports list no open critical findings.

Critical findings
No open critical findings
Across 3 reports.
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.

Audits3

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Quadrata Passport - Audit (Addendum)Security firm: CertiKDate: Scope: Files named in the reportNo open critical findingsOpen · skynet.certik.com
Quadrata LendingSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com
Quadrata Passport Audit 2Security firm: CertiKDate: Scope: Files named in the reportNo open critical findingsOpen · skynet.certik.com

Findings34

Statuses are the security firm’s own, from each report.

SeverityOpenAcknowledgedFixed
Critical000
High331
Medium052
Low3611
HighCentralization Related RisksQuadrata Passport - Audit (Addendum) · CertiK · 3 Jul 2023Acknowledged

In the contract `QuadGovernance` the role `DEFAULT_ADMIN_ROLE` is the admin of `GOVERNANCE_ROLE`. In the contract `QuadGovernance` the role `GOVERNANCE_ROLE` is the admin of `PAUSER_ROLE`, `ISSUER_ROLE` and `READER_ROLE`, and also has authority over the functions below. - function setTreasury() - function setPassportContractAddress() - function updateGovernanceInPassport() - function acceptGovernanceInPassport() - function setEligibleAttribute() - function setEligibleAttributeByDID() - function setPreapprovals() - function setAttributePriceFixed() - function setBusinessAttributePriceFixed() - function setRevSplitIssuer() - function addIssuer() - function deleteIssuer() - function setIssuerStatus() - function setIssuerAttributePermission() - function _authorizeUpgrade(): upgrade contract. In the contract `QuadGovernance` the role `OPERATOR_ROLE` has authority over the function below. - function setTokenURI() In the contract `QuadPassport` the role `GOVERNANCE_ROLE` of `QuadGovernance` contract has authority over the functions below. - function withdraw(): withdraw received fees to an issuer's treasury. - function setQuadReader(): set `reader` contract. - function migrateAttributes(): migrate attributes from `_attributes` to `_attributesv2`. - function _authorizeUpgrade(): upgrade contract. In the contract `QuadPassport` the role `PAUSER_ROLE` of `QuadGovernance` contract has authority over the functions below. - function pause() - function unpause() In the contract `QuadPassport` the role `ISSUER_ROLE` of `QuadGovernance` contract has authority to sign passport configuration data, which can be used to update passports. In the contract `QuadPassport` the role `READER_ROLE` of `QuadGovernance` contract has authority over the functions below. - function attribute(): get one attribute information about a passport. - function attributes(): get all attribute information about a passport. In the contract `QuadReader` the role `GOVERNANCE_ROLE` of `QuadGovernance` contract has authority over the functions below. - function withdraw() - function _authorizeUpgrade(): upgrade contract. `QuadPassport`, `QuadSoulbound`, `QuadReader` and `QuadGovernance` are upgradeable contracts, the owner can upgrade the contract without the community's commitment. Any compromise to the privileged account may allow the hacker to take advantage of this authority.

Open the report
HighCentralization Related RisksQuadrata Passport Audit 2 · CertiK · 23 Sep 2022Acknowledged

In the contract `QuadGovernance`, the role `GOVERNANCE_ROLE` has authority over functions. Any compromise to the `GOVERNANCE_ROLE` account may allow the hacker to take advantage of this authority and - set QuadPassport treasury wallet to withdraw the protocol fees through `setTreasury()` - set QuadPassport contract address through `setPassportContractAddress()` - begin transfer of `GOVERNANCE_ROLE` through `updateGovernanceInPassport()` - accept transfer of `GOVERNANCE_ROLE` through `acceptGovernanceInPassport()` - set the eligibility status for a passport token ID through `setEligibleTokenId()` - set the eligibility status for an attribute type through `setEligibleAttribute()` - set the eligibility status for an attribute type grouped by DID through `setEligibleAttributeByDID()` - set the price for querying a single attribute after owning a passport through `setAttributePriceFixed()` - set the business attribute price for querying a single attribute after owning a passport through `setBusinessAttributePriceFixed()` - set the revenue split percentage between issuers and Quadrata Protocol through `setRevSplitIssuer()` - add a new issuer or update treasury through `addIssuer()` - delete issuer through `deleteIssuer()` - deactivate/activate issuer through `setIssuerStatus()` - set which attributes an issuer can attest to through `setIssuerAttributePermission()` - authorize to upgrade QuadGovernance contract through `_authorizeUpgrade()` In the contract `AccessControlUpgradeable`, each role has an associated `adminRole` account and the `adminRole` account has the authority over functions. Any compromise to the `adminRole` accounts may allow the hacker to take advantage of this and - grant a specific `role` to any arbitrary addresses through `grantRole()` - revoke a specific `role` from `account` through `revokeRole()` In the contract `QuadPassport`, the role `pendingGovernance` has authority over function `acceptGovernance()`. Any compromise to the `GOVERNANCE_ROLE` account may allow the hacker to take advantage of this authority and - accept the role `governance` In the contract `QuadPassport`, the role `GOVERNANCE_ROLE` has authority over functions. Any compromise to the `GOVERNANCE_ROLE` account may allow the hacker to take advantage of this authority and - withdraw revenue to an issuer's treasury through `withdraw()` - authorize to upgrade QuadPassport contract through `_authorizeUpgrade()` - migrate passports from an older contract through `migrate()` In the contract `QuadPassport`, the role `READER_ROLE` has authority over function `attributes()`. Any compromise to the `READER_ROLE` account may allow the hacker to take advantage of this authority and - get attribute information about a passport holder In the contract `QuadPassport`, the role `ISSUER_ROLE` has authority over functions. Any compromise to the `ISSUER_ROLE` account may allow the hacker to take advantage of this authority and - burn an account's Quadrata passport or delete passport attributes through `burnPassportIssuer()` - update or set a new attribute for your passport through `setAttributesIssuer()` In the contract `QuadReader`, the role `GOVERNANCE_ROLE` has authority over functions. Any compromise to the `GOVERNANCE_ROLE` account may allow the hacker to take advantage of this authority and - authorize to upgrade QuadReader contract through `_authorizeUpgrade()` - withdraw revenue to an issuer's treasury or the Quadrata treasury through `withdraw()`

Open the report
HighCentralized Control of Contract UpgradeQuadrata Passport Audit 2 · CertiK · 23 Sep 2022Acknowledged

`QuadPassport`, `QuadSoulbound`, `QuadReader` and `QuadGovernance` are upgradeable contracts, the owner can upgrade the contract without the community's commitment. If an attacker compromises the account, he can change the implementation of the contract and drain tokens from the contract.

Open the report
MediumIncomplete passport burning in `burnPassports()`Quadrata Passport - Audit (Addendum) · CertiK · 3 Jul 2023Acknowledged

The `burnPassports()` and `burnPassportsIssuer()` functions are used to burn users' passports with all attributes. These functions iterate through the `eligibleAttributesArray` array, which contains eligible attributes. However, there may be other attributes that are true in the `_eligibleAttributesByDID` mapping that are not included in the `eligibleAttributesArray`. As a result, the `burnPassports()` and `burnPassportsIssuer()` functions may not burn all passports.

Open the report
MediumReuse of signed messages in `_setAttributesVerifyQuadrata Passport - Audit (Addendum) · CertiK · 3 Jul 2023Acknowledged

The function `_setAttributesVerify()` does not check whether a `signedMsg` has been used before. This means that a `signedMsg` can be reused, potentially allowing a user to recover a passport after it has been removed.

Open the report
MediumRisk of Data Loss After Passport MigrationQuadrata Passport - Audit (Addendum) · CertiK · 3 Jul 2023Acknowledged

The current migration process involves removing the previous data right after the migration. However, this practice is not recommended as it can lead to the loss of important data in case of unexpected errors or issues.

Open the report
Medium`supportsInterface()` not properly implementedQuadrata Passport Audit 2 · CertiK · 23 Sep 2022Acknowledged

The `QuadSoulbound` contract does not implement all ERC1155 functions, but the `supportsInterface()` function implies it supports ERC1155 interface. For interface checking, the `QuadSoulbound` contract should inherit from ERC165 contract and add super contract interface checking. Otherwise the interface checking functionality will malfunction in many cases. See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.2/contracts/utils/introspection/ERC165.sol

Open the report
MediumMissing Fields in SignatureQuadrata Passport Audit 2 · CertiK · 23 Sep 2022Acknowledged

An issuer can use a signature to modify the passport attribute of any eligible id since the issuer signature does not contain the `_config.tokenId` field. For security concerns, a signature should include `_config.attrTypes`, too.

Open the report
LowDeleted Issuer's Treasury Address Should Be RemovQuadrata Passport - Audit (Addendum) · CertiK · 3 Jul 2023Acknowledged

The `_issuerTreasury` map stores the issuer's treasury address. The `addIssuer()` function sets this address for the new issuer, but the `deleteIssuer()` function doesn't remove the deleted issuer's treasury address, which causes inconsistency in state.

Open the report
LowMissing Check `_deletedIssuers` Before Adding NewQuadrata Passport - Audit (Addendum) · CertiK · 3 Jul 2023Acknowledged

The deleted issuer will be saved in the `_deletedIssuers` array. The `addIssuer()` function doesn't check whether the new issuer to be added is in the `_deletedIssuers` array. Therefore, the rejoined issuer may exist in both the `_issuers` and `_deletedIssuers` arrays at the same time.

Open the report
Show 4 more
LowPotential incomplete return value of `attribute()Quadrata Passport - Audit (Addendum) · CertiK · 3 Jul 2023Acknowledged

```solidity function attribute( address _account, bytes32 _attribute ) public view override returns (Attribute memory) { require(msg.sender == address(reader) || IAccessControlUpgradeable(address(governance)).hasRole(READER_ROLE, _msgSender()), "INVALID_READER"); address[] memory issuers = governance.getIssuers(); for (uint256 i = 0; i < issuers.length; i++) { bytes32 attrKey = attributeKey(_account, _attribute, issuers[i]); Attribute memory attr = _attributesv2[attrKey]; if (attr.epoch != uint256(0)) { attr.issuer = issuers[i]; return attr; } } return Attribute({value: bytes32(0), epoch: uint256(0), issuer: address(0)}); } ``` The `attribute()` function in the contract is designed to return a single `Attribute` struct for the inputted `_account` and `_attribute`. However, if multiple issuers sign the same `_attribute` for the `_account`, there could be multiple `Attribute` structs, potentially leading to data inconsistency issues and confusion in the passport verification process.

Open the report
LowPotential issues about new State VariablesQuadrata Passport - Audit (Addendum) · CertiK · 3 Jul 2023Acknowledged

```solidity contract QuadGovernanceStoreV2 is QuadGovernanceStore { address[] internal _deletedIssuers; mapping(address => bool) internal _preapprovals; } ``` ```solidity contract QuadGovernance is IQuadGovernance, AccessControlUpgradeable, UUPSUpgradeable, QuadGovernanceStoreV2 { ``` In the current design, a new contract `QuadGovernanceStoreV2` is created by inheriting from an existing contract `QuadGovernanceStore`, which is then inherited by the implementation contract `QuadGovernance`. This approach is not recommended because if a developer upgrades `QuadGovernance` in the future without looking at the previous version, it is possible that new state variables that conflict with existing storage slots will be introduced to the new `QuadGovernance` contract. Contract `QuadPassportStoreV2` shares the same issue.

Open the report
LowPotential Issues About Attributes' EligibilitiesQuadrata Passport Audit 2 · CertiK · 23 Sep 2022Acknowledged

Functions `setEligibleAttribute()` and `setEligibleAttributeByDID()` in contract `QuadGovernance` can update the eligibility of any attribute, misuses of these functions may cause issues. For example: 1. Function `QuadPassport._validateDid()` would be invalid if `ATTRIBUTE_DID` is not eligible, which may cause the function call of `QuadPassport._setAttributesInternal()` fail. 2. Changing the eligibility of an attribute after a passport's attribute was set may cause the latter to be invalid.

Open the report
LowWhether `QuadPassport.pendingGovernance` Needs toQuadrata Passport Audit 2 · CertiK · 23 Sep 2022Acknowledged

Function `QuadGovernance.acceptGovernanceInPassport()`: ```solidity function acceptGovernanceInPassport() external { require(hasRole(GOVERNANCE_ROLE, _msgSender()), "INVALID_ADMIN"); _passport.acceptGovernance(); } ``` Function `QuadPassport.acceptGovernance()`: ```solidity function acceptGovernance() external override { require(_msgSender() == pendingGovernance, "ONLY_PENDING_GOVERNANCE_CONTRACT"); address oldGov = address(governance); governance = IQuadGovernance(pendingGovernance); pendingGovernance = address(0); emit GovernanceUpdated(oldGov, address(governance)); } ``` The address `QuadPassport.pendingGovernance` has two ways to be the `governance` of contract `QuadPassport`: 1. Get the `GOVERNANCE_ROLE` in the current governance and call `QuadGovernance.acceptGovernanceInPassport()`. 2. Call `QuadPassport.acceptGovernance()` (without the `GOVERNANCE_ROLE`) The first way needs `QuadPassport.pendingGovernance` to get `GOVERNANCE_ROLE`, while the second way does not.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="quadrata"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us