#47377 [SC-Insight] No Restriction on Self Transfer

Submitted on Jun 13th 2025 at 06:38:07 UTC by @Catchme for IOP | Paradex

  • Report ID: #47377

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/tradeparadex/audit-competition-may-2025/tree/main/paraclear

  • Impacts:

    • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

    • Contract fails to deliver promised returns, but doesn't lose value

Description

Brief/Intro

The detect_transfer_restriction() function in the Registry contract fail to restrict self-transfers. This oversight allows an account to transfer assets to itself, which is typically undesirable and should be restricted for the sake of security and data integrity. The lack of a self-transfer restriction may lead to unintended asset movements and can complicate the tracking and monitoring of user activity.

Vulnerability Details

In the detect_transfer_restriction() function, there is no check to identify whether the sender and recipient are the same account. This allows an account to perform self-transfers, which is often undesirable or unnecessary, and can be exploited in various attack vectors, such as token manipulation or fund misappropriation.

Self-transfers typically should be restricted or at least closely monitored, as they may bypass certain business rules and cause confusion in transaction logs. This missing check introduces a gap in transaction validation and can lead to data inconsistencies, unexpected behavior, or regulatory concerns.

Vulnerable Code Location

  • detect_transfer_restriction() function

// Missing self-transfer check
if sender_is_operator {
    return TransferRestriction::InvalidTransferPair.into();
}
if sender_is_sub_operator {
    return TransferRestriction::InvalidTransferPair.into();
}
if sender_is_auxiliary {
    return TransferRestriction::InvalidTransferPair.into();
}

Impact Details

Unrestricted self-transfers could violate transaction monitoring or regulatory requirements.

Proof of Concept

Proof of Concept

use crate::tests::test_utils::{RECEIVER, deploy_registry};

#[test]
fn test_detect_transfer_restriction_same_address() {
    let registry = deploy_registry(OWNER(), FACTORY(), PARACLEAR());
    let registry_dispatcher = IRegistryDispatcher {
        contract_address: registry.contract_address,
    };

    let sender: ContractAddress = RECEIVER();

    let invalid_pair: u8 = 1;

    start_cheat_caller_address(registry.contract_address, sender);

    assert_ne!(
        registry_dispatcher.detect_transfer_restriction(sender, sender, 100),
        invalid_pair,
        "same address should be restricted",
    );

    stop_cheat_caller_address(registry.contract_address);
}

Was this helpful?