Reproduced Exploit

Gorples — missing `xBorpaBalances` decrement in `finalizeRedeemFor`

1. finalizeRedeem correctly does xBorpaBalances[msg.sender] -= xAmount then pays Gorples. 2. finalizeRedeemFor pays via _easyFinalizeRedeem but never decrements xBorpaBalances. 3. User converts 1000 once, SYSTEM finalizes, balance stays 1000 → user redeems again → second payout. 4. HARM: 2000 Gorpl…

Jul 2024Otheraccounting3 min read

Chain

Other

Category

accounting

Date

Jul 2024

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.

Loading fork state…

Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 51279-missing-xgorplestoken-decrement-in-finalizeredeemfor-halborn. Standalone Foundry PoC and full write-up: 51279-missing-xgorplestoken-decrement-in-finalizeredeemfor-halborn_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/accounting/missing-decrement · vuln/redeem/double-claim · genome: wrong-condition · direct-drain

Reproduction: self-contained Foundry PoC with only forge-std. Full trace: output.txt. PoC: test/51279-missing-xgorplestoken-decrement-in-finalizeredeemfor-halborn_exp.sol.

AuditVault taxonomy: lang/solidity · platform/halborn · has/github · has/poc · severity/high · sector/token · genome: wrong-condition · direct-drain · reentrancy-guard · timestamp-dependence


Key info#

ImpactHIGH — after SYSTEM finalizes a redeem for a user, their internal xBorpaBalances stays inflated so they can redeem again and extract more Gorples than they converted
ProtocolGorples / EntanglexGorplesToken
Vulnerable codefinalizeRedeemFor — missing xBorpaBalances[_for] -= amount that finalizeRedeem performs
Bug classIncomplete state update on alternate code path
FindingHalborn — Gorples EVM Contracts Revision · #51279
Reporthalborn.com/audits/entangle-labs/gorples-evm-contracts-revision
SourceAuditVault
StatusAudit finding — fixed by adding the missing decrement. Local synthetic PoC.
Compiler^0.8.24 (PoC)

TL;DR#

  1. finalizeRedeem correctly does xBorpaBalances[msg.sender] -= xAmount then pays Gorples.
  2. finalizeRedeemFor pays via _easyFinalizeRedeem but never decrements xBorpaBalances.
  3. User converts 1000 once, SYSTEM finalizes, balance stays 1000 → user redeems again → second payout.
  4. HARM: 2000 Gorples extracted from a single 1000 convert.

The vulnerable code#

SOLIDITY
function finalizeRedeemFor(address _for) external onlyRole(SYSTEM) {
    uint256 len = userRedeems[_for].length;
    while (len > 0) {
        RedeemInfo storage _userRedeem = userRedeems[_for][len - 1];
        bool finalized = _easyFinalizeRedeem(_for, _userRedeem.xBorpaAmount, _userRedeem.endTime); // @> VULN
        // missing: xBorpaBalances[_for] -= _userRedeem.xBorpaAmount;
        ...
    }
}

Root cause#

Two finalize paths diverged: the user-facing path updates internal balances; the SYSTEM batch path only pays out.

Preconditions#

  • User has converted Gorples → x tokens and queued a redeem.
  • SYSTEM role calls finalizeRedeemFor (normal ops path).

Attack walkthrough#

  1. User converts 1000 Gorples → xBorpaBalances = 1000.
  2. User queues redeem of 1000; SYSTEM finalizes → user receives 1000 Gorples, balance still 1000.
  3. User queues and finalizes again → second 1000 Gorples.
  4. HARM: double extraction against vault inventory.

Diagrams#

flowchart TD A["convert 1000"] --> B["xBorpaBalances = 1000"] B --> C["redeem 1000"] C --> D["finalizeRedeemFor"] D --> E["pays 1000 Gorples"] D --> F["xBorpaBalances still 1000"] F --> G["redeem again"] G --> H["second 1000 Gorples payout"]

Impact#

Protocol inventory drained; users can extract more underlying than they deposited via the SYSTEM finalize path.

Sources#


Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.