M-1: PermissionedSisuVault allows unauthorized share transfers
Summary:
The PermissionedSisuVault contract is designed to restrict access to a single permissionedAddress. It achieves this by overriding the ERC4626 entry and exit functions (deposit, mint, withdraw, redeem) and applying the onlyPermissioned modifier.
However, the contract inherits from SisuVault (and subsequently ERC20) but does not override transfer or transferFrom. As a result, standard ERC20 token transfers are unrestricted.
// src/sisu_vault/PermissionedSisuVault.sol
contract PermissionedSisuVault is SisuVault {
// ... overrides for deposit, mint, withdraw, redeem ...
// MISSING: overrides for transfer / transferFrom
}
If the permissionedAddress mints shares to a receiver (e.g., a partner or a specific treasury wallet), that receiver can freely transfer those shares to any other address.
Description:
The PermissionedSisuVault inherits from SisuVault, which in turn inherits from ERC4626 (and ERC20).
- Inheritance Chain:
PermissionedSisuVault->SisuVault->ERC4626->ERC20. - Overrides: The contract correctly overrides
deposit,mint,withdraw, andredeemto enforce theonlyPermissionedmodifier. - Missing Overrides: The standard ERC20 functions
transferandtransferFromare not overridden. - Result: Once shares are minted to an address (even if that address was initially approved/permissioned), that address can call
transferto move the shares to any other address, bypassing the permissioned gateway.
Impact:
This oversight allows for the circumvention of the "permissioned" nature of the vault regarding share ownership.
- Unauthorized Ownership: An authorized share holder can transfer shares to an unauthorized or blacklisted entity.
- Invariant Violation: The audit scope document states "Only Usual should be allowed to supply USD0 for borrowing". If shares (which represent the supplied capital) can be transferred to third parties without restriction, the protocol loses control over who effectively owns the supplied capital.
While the unauthorized holder cannot call withdraw (as that is restricted to permissionedAddress), they legally/technically own the claim on the underlying assets.
Recommendation:
Override transfer and transferFrom to enforce access control, or disable transfers entirely if the shares are intended to be non-transferable (soulbound) to ensure only the permissionedAddress (or receivers explicitly minted to) can hold them.
If the intention is to allow transfers only between whitelisted entities, logic should be added to check both from and to against a whitelist or restrict initiation to permissionedAddress.
Developer Response:
Acknowledged - won't fix. Operationally, we only expect the owner to hold shares in the vault and not to transfer any tokens, so we don't see any need to implement any precaution here.