ParaSpace pcAPE / cAPE Third-Party ApeStaking Recipient Inflation Near Miss (2023-03-17)

  • Name: ParaSpace pcAPE / cAPE third-party ApeStaking recipient inflation near miss
  • Date: 2023-03-17
  • Protocol: ParaSpace
  • Chain: Ethereum
  • Category: donation / share-price manipulation / oracle manipulation / third-party recipient inflation / rescued near miss
  • Loss: near miss; BlockSec reported that about 2,906 to 2,909 ETH of withdrawals were rescued before the main drain completed, while ParaSpace later said realized protocol losses were only about 50 to 150 ETH from attacker swap slippage and that no NFTs were compromised
  • Summary: ParaSpace let users borrow against pcAPE, a collateral token whose value depended on cAPE’s live rebasing index. That index ultimately read ApeCoinStaking.addressPosition(address(this)).stakedAmount + pendingRewards + bufferBalance through cAPE’s getPooledApeByShares() path. The crucial mistake was that ApeCoin staking also exposed depositApeCoin(uint256 _amount, address _recipient), so anyone could deposit raw APE directly into the staking position owned by the cAPE contract by choosing recipient = address(cAPE). That increased the pooled-APE numerator without minting matching cAPE shares. The attacker used flash-loaned capital to build a large pcAPE collateral position, then donated more than 2.33M APE into cAPE’s underlying staking position, pushing the rebasing index sharply upward and making the same pcAPE collateral appear far more valuable than it really was. Three attack attempts failed on gas limits before succeeding economically; BlockSec then raced the attacker and sent a rescue transaction that withdrew roughly 2,906 ETH first.
  • Trigger / entry point:
    • ParaSpace treated pcAPE as collateral and valued it with a rebasing index derived from cAPE’s lastRebasingIndex() / getPooledApeByShares() path.
    • getPooledApeByShares() used _getTotalPooledApeBalance(), which counted the stakedAmount and pending rewards of the ApeCoin staking position owned by the cAPE contract.
    • ApeCoin staking’s depositApeCoin(uint256 _amount, address _recipient) let arbitrary callers increase addressPosition[_recipient].stakedAmount for any chosen recipient address.
    • ParaSpace therefore consumed a live exchange rate whose numerator could be increased by third parties without issuing corresponding new wrapper shares.
  • Root cause:
    • ParaSpace collapsed raw APE newly attributable to the cAPE staking position and share-backed value belonging to existing cAPE / pcAPE holders into the same price object.
    • The protocol assumed growth in cAPE’s pooled APE balance represented honest reward accrual or user-backed staking value, but the underlying ApeCoin staking contract also allowed arbitrary third-party deposits into that same recipient position.
    • Because the lending layer honored the resulting rebasing index as collateral truth, a donation-like increase in the numerator immediately became borrow power.
    • The bug was not just oracle manipulation in the loose sense. It was a wrapper-rate design failure: ParaSpace trusted a rebasing collateral mark that did not prove the extra underlying APE had arrived through the share-mint path that should have backed outstanding claims.
  • Exploit path:
    1. The attacker prepared capital and deployed an attack contract on 2023-03-17.
    2. They flash-borrowed roughly 47,352 wstETH, supplied about 46,018 wstETH, and used the position to borrow large amounts of cAPE.
    3. They deposited roughly 12,880,000 cAPE as collateral in ParaSpace, receiving the corresponding pcAPE exposure whose value depended on the rebasing index.
    4. They swapped part of the borrowed capital into APE and withdrew roughly 1,839,999 cAPE back into APE needed for the inflation leg.
    5. They called ApeCoinStaking.depositApeCoin() with recipient = address(cAPE), depositing about 2,332,214 APE into the staking position that cAPE used as its backing source.
    6. That donation-like deposit reportedly increased the tracked pooled stake from about 851,662 APE to about 3,183,876 APE, pushing the rebasing index up by roughly 3.73x without minting proportional new cAPE shares.
    7. ParaSpace then treated the same pcAPE collateral as much more valuable, opening the door to oversized USDC / WETH borrowing and withdrawal.
    8. The attacker tried three times to complete the drain, but the transactions failed because the configured gas limit was too low for the full attack path.
    9. After observing the failed attempts, BlockSec prepared a rescue contract and sent its own transaction first, rescuing about 2,906 ETH before the attacker could make another successful attempt.
  • What the attacker needed to be true:
    • ParaSpace had to accept pcAPE as collateral and price it directly from cAPE’s live rebasing index.
    • cAPE’s rebasing index had to depend on a pooled-APE numerator that treated third-party APE deposits into address(cAPE)’s staking position as real backing.
    • The attacker needed enough capital to accumulate a large pcAPE position before inflating the index.
    • Large withdrawals had to remain possible quickly enough that the attacker could monetize the inflated collateral before a pause or rescue.
  • Technical anatomy worth remembering:
    • This was a donation-style wrapper-rate inflation attack disguised as a staking / rebasing collateral oracle.
    • The decisive seam was recipient-controlled underlying staking balance rather than a thin AMM venue. Anyone who could name address(cAPE) as the recipient could change the numerator of the collateral mark.
    • The dangerous accounting object was pcAPE amount * rebasingIndex. Once the rebasing index lost its claim to share-backed value, ParaSpace’s collateral engine started honoring donated APE as if it were earned or minted backing.
    • The attack also shows why rebasing wrapper marks need stronger provenance than the underlying position balance increased: the key question is whether the increase arrived through the wrapper’s own issuance boundary.
    • The three failed transactions matter because they show the exploit was economically viable before the rescue; the first failed runs were mainly blocked by operational gas settings, not by protocol-level solvency checks.
  • Representative code and transaction artifacts:
    • cAPE pricing path highlighted by BlockSec: lastRebasingIndex() → getPooledApeByShares(uint256 sharesAmount) → _getTotalPooledApeBalance()
    • Underlying staking entrypoint: ApeCoinStaking.depositApeCoin(uint256 _amount, address _recipient)
    • Failed attack attempt 1 (gasLimit = 6,721,975): 0x161427ac3bfa8047fefaf505f50dc792840c4824d4773760939aa7eaa270e3d9
    • Failed attack attempt 2 (gasLimit = 9,000,000): 0xc7c8bf8ebacaf72d4cba3f7c69c770060bd32b3892697226f9bb9a871a1c1f62
    • Failed attack attempt 3 (gasLimit = 13,000,000): 0xe92b91f4dd13218a24e7328298e4a015cdbe74f3f10ccf60666300a508186e18
    • Rescue transaction: 0xe3f0d14cfb6076cabdc9057001c3fafe28767a192e88005bc37bd7d385a1116a
  • Response / mitigation:
    • ParaSpace paused the protocol while patching the vulnerability.
    • The team stated that all user funds were safe, no NFTs were compromised, and the roughly 2,909 ETH targeted for withdrawal had been rescued with BlockSec’s help.
    • ParaSpace said realized protocol losses were limited to about 50 to 150 ETH of slippage from the attacker’s swaps and that it would reimburse those losses.
    • The team also said it would re-audit the platform, add additional security review, and introduce timelocks for large withdrawals before resuming normal operation.

Why this incident matters

  • It is a clean example of a collateral wrapper whose exchange-rate numerator could be inflated by third-party deposits into the wrapper’s own underlying position, not by direct donations to the wrapper contract itself.
  • The note is useful because the exploit surface sat one layer deeper than the lending market: the wrapper’s upstream staking integration quietly decided what counted as backing.
  • It also preserves a recurring lesson for reward-bearing and rebasing collateral: if outsiders can increase the assets per share numerator without crossing the wrapper’s own issuance boundary, the wrapper’s price is already an attacker-controlled solvency object.
  • The sharper healthy-side boundary is that the wrapper's recipient-owned staking balance went up should not have meant existing wrapper shares now deserve proportionally more lending authority. ParaSpace needed a stronger provenance test than upstream pooled balance increased before pcAPE could publish that growth as collateral truth.

Pattern tags:

  • Upstream-recipient inflation: ApeCoinStaking.depositApeCoin(uint256 _amount, address _recipient) let arbitrary callers increase the staking position owned by address(cAPE) without going through cAPE minting.
  • Wrapper-backing provenance failure: cAPE’s rebasing numerator treated third-party-deposited APE in addressPosition(address(this)) as if it were share-backed pooled value.
  • Rebasing-collateral publication failure: ParaSpace multiplied pcAPE balances by the live rebasingIndex and let that wrapper-side mark become immediate borrowing power.
  • Truthful local state, unsafe downstream trust: neither ApeCoinStaking nor cAPE had to lie about balances; the lending market overtrusted a real-but-unauthorized increase in upstream backing.
  • Design companions: donation-share-price-manipulation, balance-delta-provenance-failure, vault-share-truth-security-object, and reward-recognition-presentation-and-collateral-separation.

Why the exploit worked

  • The attacker could first accumulate a large pcAPE collateral position, so the later numerator inflation applied to a meaningful existing share base they already controlled.
  • ApeCoin staking exposed a public third-party recipient rail, which meant outsiders could increase the pooled APE attributed to cAPE without receiving new cAPE shares.
  • cAPE’s rebasing path collapsed recipient-owned staking balance increased and wrapper backing per share legitimately increased into the same number.
  • ParaSpace then treated that rebasing index as immediate collateral truth rather than as a presentation layer value that still needed provenance checks, caps, or quarantine.
  • Once the lending layer accepted the inflated wrapper mark, the wrapper bug and the lending bug became one joined solvency surface: attacker-authored upstream balance growth immediately meant more borrowable value.

Detection and audit pivots

  • Review every wrapper or rebasing collateral that prices itself from an upstream recipient-owned staking or reward position. Ask who else can increase that position without minting proportional wrapper shares.
  • Distinguish balance increased from share-backed value increased. If a wrapper reads raw staked balance, pending rewards, or ambient token receipts, document which rails are allowed to change collateral truth.
  • Trace whether a wrapper’s rebasingIndex, balanceOf, convertToAssets, or exchange-rate helper can be changed by third-party transfers or deposits one layer below the wrapper itself.
  • Fuzz the exact large existing share holder + third-party upstream deposit + immediate collateral revaluation sequence, not only direct donation into the wrapper contract.
  • Treat reward-bearing wrappers as structured collateral, not passive tokens: apply borrow caps, listing haircuts, delayed collateral enablement, or sanity bounds until the wrapper’s backing provenance is explicit and hard to spoof.

Failure-prevention checklist

  • Treat every upstream staking or rewards recipient parameter as a custody rail, not just an integration convenience. If outsiders can credit value to the wrapper-owned position, that credited value must stay quarantined or non-borrowable until the wrapper explicitly decides how to recognize it.
  • Keep wrapper-share issuance, upstream-balance recognition, and downstream collateral publication as separate gates. cAPE-side pooled-balance growth should not have become immediate pcAPE borrow power without an additional provenance check or risk haircut.
  • For rebasing wrappers, document exactly which paths may move the rebasing numerator: direct deposits, wrapper minting, reward harvest, third-party top-ups, rescues, migrations, and operator sync calls. Anything not on the allowlist should not reprice collateral.
  • Apply borrow caps, isolated-mode listing, or delayed collateral admission to wrappers whose backing comes from mutable upstream positions rather than from directly custodied underlying assets.
  • Stress-test large incumbent share owner + upstream recipient deposit + same-block collateral revaluation + borrow as a standard scenario, especially when the upstream position belongs to address(this) and the underlying protocol exposes recipient-controlled deposits.
  • Add monitors for abrupt numerator jumps in wrapper exchange rate or rebasing index that are not explained by plausible reward accrual, and give operators a fast way to pause collateral use before large withdrawals settle.
  • If the wrapper is expected to auto-compound or rebase, make the review surface explicit: who can cause backing growth, who can publish it, and which downstream modules are allowed to honor it.

Audit prompts

  • Can any external caller increase the upstream balance, rewards, or staking position attributed to the wrapper contract without minting new wrapper shares?
  • Does the wrapper treat recipient-owned position grew as automatically equivalent to existing shares are better backed, or is there an explicit recognition boundary between those two states?
  • Which exact function turns upstream position state into user-facing value: rebasingIndex, balanceOf, convertToAssets, cached NAV, or a lending-market adapter? Where is the last chance to reject untrusted growth before it becomes solvency truth?
  • If a third party donates assets one layer below the wrapper, does the protocol quarantine that growth, haircut it, ignore it, or let it become immediate collateral value?
  • What stops a large incumbent holder from inflating the numerator upstream and monetizing the higher wrapper mark through same-block borrow, self-liquidation, or recursive collateral loops?
  • Are large wrapper-rate moves bounded against realistic reward schedules, or can an arbitrary upstream deposit make the wrapper appear to have earned months of yield in one transaction?
  • Who can pause or de-recognize the wrapper if upstream backing semantics prove weaker than the lending market assumed?

Lessons that should already be standard

  • Upstream recipient can be credited by third parties is already a price-oracle problem if downstream systems treat the resulting wrapper rate as collateral truth.
  • A rebasing index is not merely presentation math. Once borrowing power depends on it, the full provenance of its numerator belongs inside the security boundary.
  • Real balance growth is not the same thing as authorized balance growth. ParaSpace mostly read truthful upstream state; the failure was deciding that every truthful increase deserved to reprice existing claims.
  • Wrapper review has to look one layer deeper than the wrapper contract. The dangerous rail here lived in ApeCoinStaking’s recipient model, not in a direct donate() function on cAPE itself.
  • Rescue success should not hide exploit viability. The failed attacker transactions mattered because they showed the solvency break was real before BlockSec won the race.
  • Reward-bearing or rebasing collateral needs a stricter publication policy than spot assets. If the wrapper can self-author a faster mark than the market can safely absorb, collateral admission has to lag or haircut that mark.

Internal linkages

Control surface