sherlock-audit / 2024-09-orderly-network-solana-contract-judging

0 stars 0 forks source link

Fit Canvas Pangolin - In the deposit() function, due to the lack of a check on deposit_token, an attacker can use the Mint of any token to replace the Mint of USDC. #95

Open sherlock-admin3 opened 4 days ago

sherlock-admin3 commented 4 days ago

Fit Canvas Pangolin

High

In the deposit() function, due to the lack of a check on deposit_token, an attacker can use the Mint of any token to replace the Mint of USDC.

Summary

In the deposit() function, due to the lack of a check on deposit_token, an attacker can use the Mint of any token to replace the Mint of USDC.

Root Cause

https://github.com/sherlock-audit/2024-09-orderly-network-solana-contract/blob/main/solana-vault/packages/solana/contracts/programs/solana-vault/src/instructions/vault_instr/deposit.rs#L22

pub struct Deposit<'info> {
    #[account(mut)]
    pub user: Signer<'info>,

    #[account(
        mut,
@>>        associated_token::mint = deposit_token,
        associated_token::authority = user
    )]
    pub user_token_account: Box<Account<'info, TokenAccount>>,

    #[account(
        mut,
        seeds = [VAULT_AUTHORITY_SEED],
        bump = vault_authority.bump,
    )]
    pub vault_authority: Box<Account<'info, VaultAuthority>>,

    #[account(
        init_if_needed,
        payer = user,
@>>        associated_token::mint = deposit_token,
        associated_token::authority = vault_authority
    )]
    pub vault_token_account: Box<Account<'info, TokenAccount>>,

    #[account()]
@>>    pub deposit_token: Box<Account<'info, Mint>>,

    #[account(
        seeds = [
            PEER_SEED,
            &oapp_config.key().to_bytes(),
            &vault_authority.dst_eid.to_be_bytes()
        ],
        bump = peer.bump
    )]
    pub peer: Box<Account<'info, Peer>>,

    #[account(
        seeds = [
            ENFORCED_OPTIONS_SEED,
            &oapp_config.key().to_bytes(),
            &vault_authority.dst_eid.to_be_bytes()
        ],
        bump = enforced_options.bump
    )]
    pub enforced_options: Box<Account<'info, EnforcedOptions>>,

    #[account(
        seeds = [OAPP_SEED],
        bump = oapp_config.bump
    )]
    pub oapp_config: Box<Account<'info, OAppConfig>>,

    #[account(
        seeds = [BROKER_SEED, deposit_params.broker_hash.as_ref()],
        bump = allowed_broker.bump,
        constraint = allowed_broker.allowed == true @ VaultError::BrokerNotAllowed
    )]
    pub allowed_broker: Box<Account<'info, AllowedBroker>>,

    #[account(
        seeds = [TOKEN_SEED, deposit_params.token_hash.as_ref()],
        bump = allowed_token.bump,
        constraint = allowed_token.allowed == true @ VaultError::TokenNotAllowed
    )]
    pub allowed_token: Box<Account<'info, AllowedToken>>,

    pub token_program: Program<'info, Token>,
    pub associated_token_program: Program<'info, AssociatedToken>,
    pub system_program: Program<'info, System>,
}

It can be observed that there is no check or constraint on deposit_token.

Although there are related checks for allowed_token, such as requiring allowed_token.allowed == true, deposit_params is a user input parameter. A user could set deposit_params.token_hash to usdc_hash, but this is not actually linked to the USDC Mint.

As a result, an attacker can use the minting of any arbitrary token instead of USDC’s Mint, allowing them to deposit worthless tokens in place of USDC. When there is USDC deposited by other users in the vault_token_account, the attacker can initiate a withdrawal request and take out the USDC.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

1.  The attacker uses a worthless Token Mint to perform a deposit (with all other parameters set correctly).
2.  They wait until there is USDC in the vault_token_account from other users’ deposits (or USDC added by the protocol).
3.  They initiate a withdrawal to take out the USDC.

Impact

The protocol has lost valuable tokens, specifically USDC.

PoC

No response

Mitigation

#[account(
        seeds = [OAPP_SEED],
        bump = oapp_config.bump,
+        constraint = oapp_config.usdc_mint == deposit_token
    )]
pub oapp_config: Box<Account<'info, OAppConfig>>,