Dria

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

Role Separation Violation in Swan Protocol

Summary

Vulnerability in Swan.sol where role separation between operators and owners can be bypassed through delegation, allowing privilege escalation.

we can see the operator assignments in initialize(): https://github.com/Cyfrin/2024-10-swan-dria/blob/c3f6f027ed51dd31f60b224506de2bc847243eb7/contracts/swan/Swan.sol#L141-L144

// swan is an operator
isOperator[address(this)] = true;
// owner is an operator
isOperator[msg.sender] = true;

This is a bug because:

  1. The contract allows the owner to also be an operator

  2. The delegated access system doesn't prevent an operator from being delegated access by a user who is also the owner

  3. This creates a path where role separation can be violated by having the owner's privileges leak through operator delegation

Vulnerability Details

In Swan.sol#list: https://github.com/Cyfrin/2024-10-swan-dria/blob/c3f6f027ed51dd31f60b224506de2bc847243eb7/contracts/swan/Swan.sol#L157-L182

function list(string calldata _name, string calldata _symbol, bytes calldata _desc, uint256 _price, address _buyer)
external
{
BuyerAgent buyer = BuyerAgent(_buyer);
(uint256 round, BuyerAgent.Phase phase,) = buyer.getRoundPhase();
// buyer must be in the sell phase
if (phase != BuyerAgent.Phase.Sell) {
revert BuyerAgent.InvalidPhase(phase, BuyerAgent.Phase.Sell);
}
// @bug detected: Missing validation of _buyer address being a valid BuyerAgent contract
// Attacker can pass any address that implements getRoundPhase() function
// @bug detected: No zero address check for _buyer
// Could lead to assets being listed with invalid buyer addresses
// @bug detected: No price validation
// Assets could be listed with zero or extremely high prices
address asset = address(swanAssetFactory.deploy(_name, _symbol, _desc, msg.sender));
listings[asset] = AssetListing({
createdAt: block.timestamp,
royaltyFee: buyer.royaltyFee(),
price: _price,
seller: msg.sender,
status: AssetStatus.Listed,
buyer: _buyer,
round: round
});

For Swan.sol's initialization and access control logic: https://github.com/Cyfrin/2024-10-swan-dria/blob/c3f6f027ed51dd31f60b224506de2bc847243eb7/contracts/swan/Swan.sol#L118-L145

function initialize(...) public initializer {
__Ownable_init(msg.sender);
// <@bug detected: Owner automatically becomes operator
isOperator[msg.sender] = true;
// <@bug detected: Contract becomes operator
isOperator[address(this)] = true;
}
function list(string calldata _name, ..., address _buyer) external {
// <@bug detected: No validation of buyer legitimacy
BuyerAgent buyer = BuyerAgent(_buyer);
// <@bug detected: External call to unverified contract
(uint256 round, BuyerAgent.Phase phase,) = buyer.getRoundPhase();
}

Impact:

  1. The function accepts any address as _buyer without verifying it was created through the official BuyerAgentFactory. This allows malicious actors to create fake buyer contracts that could manipulate the market.

  2. Without price bounds validation, attackers could:

    • List assets at extreme prices affecting market statistics

    • Create overflow conditions in fee calculations

    • Potentially block legitimate transactions through gas manipulation

These vulnerabilities directly affect the core listing functionality of Swan protocol and could disrupt the marketplace operations.

Impact

  1. Breaking the trust model of verified buyer agents

  2. Allowing market manipulation through fake listings

  3. Potentially trapping seller assets with malicious buyers

Tools Used

Manual Review

Recommendations

function initialize(...) public initializer {
__Ownable_init(msg.sender);
- isOperator[msg.sender] = true;
+ require(msg.sender != owner(), "Owner cannot be operator");
}
function list(..., address _buyer) external {
+ require(buyerAgentFactory.isBuyerAgent(_buyer), "Invalid buyer");
+ require(_price > 0 && _price <= maxPrice, "Invalid price");
BuyerAgent buyer = BuyerAgent(_buyer);
}

Alternative approach:

  • Implement role hierarchy system

  • Add buyer registry validation

  • Enforce strict separation between owner and operator roles

  • Add price bounds and validation checks

  • Implement buyer contract verification system

Updates

Lead Judging Commences

inallhonesty Lead Judge
8 months ago
inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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