DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: high
Invalid

Centralization Risk for Trusted Owners in Internalizer Contract

File Location: protocol/contracts/tokens/Fertilizer/Internalizer.sol#L39-L41

Vulnerability Details

Having a single EOA as the only owner of contracts is a large centralization risk and a single point of failure. A single private key may be taken in a hack, or the sole holder of the key may become unable to retrieve the key when necessary. Consider changing to a multi-signature setup, or having a role-based authorization model.

Impact

  • Single Point of Failure

  • High Risk of Unauthorized Access

  • Inflexibility in Management

Tools Used

  • Inspection manual

  • Solidity

  • Foundry

Recommendations

To fix the centralization risk problem that occurs due to the use of a single external account (EOA) as the sole contract owner, we can replace it with a multi-signature mechanism or a role-based authorization model.

Code snippet:

L39-L41

function setURI(string calldata newuri) public onlyOwner {
_uri = newuri;
}

Fixed code:

import "@openzeppelin/contracts/access/AccessControl.sol";
contract Internalizer is AccessControl {
bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE");
string private _uri;
constructor() {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(URI_SETTER_ROLE, msg.sender);
}
modifier onlyAuthorized() {
require(hasRole(URI_SETTER_ROLE, msg.sender), "Not authorized");
_;
}
function setURI(string calldata newuri) public onlyAuthorized {
_uri = newuri;
}
}

Code when testing using Foundry:

import "@openzeppelin/contracts/access/AccessControl.sol";
contract Internalizer is AccessControl {
bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE");
string private _uri;
constructor() {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender); // Admin awal
_grantRole(URI_SETTER_ROLE, msg.sender); // URI setter awal
_setRoleAdmin(URI_SETTER_ROLE, DEFAULT_ADMIN_ROLE); // Admin bisa mengelola URI setter
}
modifier onlyAuthorized() {
require(hasRole(URI_SETTER_ROLE, msg.sender), "Not authorized");
_;
}
function setURI(string calldata newuri) public onlyAuthorized {
_uri = newuri;
}
// Untuk memastikan admin tidak bisa memodifikasi URI secara langsung tanpa peran URI_SETTER_ROLE
function grantRole(bytes32 role, address account) public override onlyRole(getRoleAdmin(role)) {
super.grantRole(role, account);
}
}

Foundry output:

Ran 2 tests for test/InternalizerTest.t.sol:InternalizerTest
[PASS] testSetURIByAuthorizedUser() (gas: 35804)
[PASS] testSetURIByUnauthorizedUser() (gas: 13370)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.27ms (422.90µs CPU time)

Ran 1 test suite in 3.94ms (1.27ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.