Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: high
Invalid

BuyerAgentFactory Passes Incorrect Operator Address Breaking Access Control

Summary

In BuyerAgentFactory, the deploy function passes msg.sender instead of the factory's address as the operator parameter to the BuyerAgent constructor.

This breaks the intended access control model as the wrong address gets operator privileges.

Vulnerability Details

The factory incorrectly passes the caller's address as operator:

contract BuyerAgentFactory {
function deploy(
string memory _name,
string memory _description,
uint96 _royaltyFee,
uint256 _amountPerRound,
address _owner
) external returns (BuyerAgent) {
return new BuyerAgent(
_name,
_description,
_royaltyFee,
_amountPerRound,
msg.sender, // Wrong: passes caller instead of factory address
_owner
);
}
}

This impacts the BuyerAgent's authorization checks:

contract BuyerAgent is Ownable {
modifier onlyAuthorized() {
// Authorization check uses wrong operator address
if (!swan.isOperator(msg.sender) && msg.sender != owner()) {
revert Unauthorized(msg.sender);
}
_;
}
constructor(
string memory _name,
string memory _description,
uint96 _royaltyFee,
uint256 _amountPerRound,
address _operator, // Gets wrong address
address _owner
) Ownable(_owner) {
swan = Swan(_operator); // Swan initialized with wrong operator
// ...
}
}

Attack Scenario:

// 1. Attacker calls factory
BuyerAgent agent = factory.deploy(
"Attack",
"Description",
royaltyFee,
amount,
owner
);
// 2. Attacker becomes operator instead of factory
// Can now:
// - Call onlyAuthorized functions
// - Make oracle requests
// - Execute purchases
// - Withdraw funds

Impact

Unauthorized addresses get operator privileges

Broken authorization model

Potential for malicious actions like Unauthorized oracle requests, purchases and withdrawals

Tools Used

Manual Review

Recommendations

Pass factory address as operator:

contract BuyerAgentFactory {
function deploy(
string memory _name,
string memory _description,
uint96 _royaltyFee,
uint256 _amountPerRound,
address _owner
) external returns (BuyerAgent) {
return new BuyerAgent(
_name,
_description,
_royaltyFee,
_amountPerRound,
address(this), // Pass factory address as operator
_owner
);
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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