The $27 million Penpie exploit on September 3, 2024, provided the DeFi community with yet another textbook example of one of the oldest smart contract vulnerabilities in existence: reentrancy. Despite being documented since the infamous 2016 DAO hack on Ethereum, reentrancy attacks continue to plague the ecosystem. This advanced tutorial dissects the Penpie attack mechanics and walks through professional auditing techniques that can identify and prevent these vulnerabilities before they reach production.
The Objective
This guide aims to equip experienced Solidity developers and security auditors with a systematic methodology for identifying reentrancy vulnerabilities in complex DeFi protocols. By the end, you will understand how the Penpie attacker combined reentrancy with permissionless market registration and flash loans to drain $27 million, and you will have practical tools to catch similar vulnerabilities in your own code reviews.
Prerequisites
This tutorial assumes familiarity with Solidity, the EVM execution model, and basic DeFi concepts. You should understand how ERC-20 token transfers work, what a flash loan is, and how yield farming protocols distribute rewards. Tools you will need: Foundry or Hardhat for local testing, Slither for static analysis, and access to a block explorer like Etherscan for transaction analysis.
Step-by-Step Walkthrough
Step 1: Understanding the Vulnerable Pattern. The Penpie exploit centered on the _harvestBatchMarketRewards() function in the PendleStakingBaseUpg contract. This function calculated staking rewards by measuring token balances before and after calling redeemRewards() on an external contract. The critical flaw: no reentrancy guard protected this function, allowing the attacker to re-enter during the external call.
The attack pattern follows a specific sequence. First, the attacker deploys a malicious SY contract that implements a callback in its redeemRewards() function. When Penpie’s contract calls this function, the malicious contract calls back into _harvestBatchMarketRewards() before the original invocation completes its state updates. This allows the attacker to claim rewards multiple times with the same deposit.
Step 2: Identifying the Attack Surface. The second critical vulnerability was permissionless market registration. Penpie’s PendleStakingBaseUpg contract allowed anyone to register new markets without validation. The attacker registered a malicious market tied to their fake SY token, which then became part of the reward distribution system. Auditing for this involves checking all external-facing registration functions and verifying they include proper validation and access controls.
Step 3: Analyzing the Flash Loan Component. The attacker used flash loans to borrow massive amounts of wstETH, sUSDe, egETH, and rswETH. These borrowed funds were deposited into the malicious SY contract during the reentrancy window, artificially inflating the token balance measured by _harvestBatchMarketRewards(). The inflated balance generated exaggerated reward claims, which the attacker then withdrew and used to repay the flash loans, pocketing the difference.
To detect flash loan amplification risks in your audits, trace all paths where external token amounts influence reward calculations. If a function measures balanceOf(this) before and after an external call, it is inherently vulnerable to balance manipulation via flash loans during the reentrancy window.
Step 4: Static Analysis with Slither. Run Slither on the target contract with the reentrancy detector: slither . --detect reentrancy. Slither identifies functions that make external calls before updating state variables. For the Penpie contract, this would have flagged _harvestBatchMarketRewards() immediately. However, static analysis has limitations — it produces false positives and can miss complex cross-contract reentrancy paths.
Step 5: Dynamic Testing with Foundry. Write a Foundry test that simulates the attack. Create a malicious contract that implements redeemRewards() with a callback to _harvestBatchMarketRewards(). Fund it with flash-loaned tokens and verify that the reward balance increases beyond what the deposit justifies. This confirms the vulnerability and quantifies the potential loss.
Step 6: Implementing the Fix. The standard remedy is to add a reentrancy guard. Using OpenZeppelin’s ReentrancyGuard modifier ensures that the function cannot be re-entered while still executing. For higher assurance, refactor the function to follow the checks-effects-interactions pattern: update all state variables before making any external calls.
Troubleshooting
Cross-contract reentrancy is harder to detect than single-contract reentrancy because the re-entry path spans multiple contracts. Use Foundry’s cheatcodes to trace all external calls during a test transaction. If an external call goes to a contract you control in testing, you have a reentrancy vector.
Another common issue is developers assuming that ERC-20 tokens are safe to call without reentrancy concerns. Some tokens implement hooks (like ERC-777) that invoke callbacks on transfers, creating reentrancy paths even in functions that only transfer tokens. Always assume external calls can re-enter.
Mastering the Skill
To go beyond basic reentrancy detection, study formal verification tools like Certora Prover and Halmos. These tools mathematically prove properties about smart contracts, catching vulnerabilities that manual audits and static analysis miss. Follow real-world exploits on platforms like Rekt News and ImmuneBytes, and reconstruct each attack in a local Foundry environment. The September 2024 DeFi hacks, with over $120 million lost, provide ample case studies. The skill that separates good auditors from great ones is the ability to think like an attacker — to see not just what the code does, but what it allows someone to do.
Disclaimer: This article is for educational purposes only. The techniques described are intended for legitimate security auditing and should not be used to exploit vulnerabilities in live protocols.
reentrancy in 2024 is wild. how do you ship a defi protocol without a reentrancy guard on withdraw functions at this point
solmaxi_v2 they probably had a reentrancy guard but only on the functions they audited. permissionless market registration creates a new entry point that wasnt in the original threat model
the DAO hack was 2016 and we are still seeing the same vulnerability pattern. audit culture in defi is fundamentally broken
the flash loan combo with permissionless registration was the real innovation here. most audits check for basic reentrancy but miss the composability angle
the composability angle is what most solo auditors miss. you can have every function individually secured but the interaction between flash loan + permissionless registration + reentrancy creates a vulnerability that only shows up in integration testing
wei c is spot on, audit culture is broken. but the real question is why penpie didnt have a bug bounty proportional to their tvl
Ana G. because bug bounties on DeFi protocols are usually capped at like $50k when the TVL is $200M+. the math doesnt work for white hats
Kasper B. bug bounties capped at 50k on a 200M TVL protocol. the math literally incentivizes black hat exploitation over responsible disclosure
Kasper B. 50k bounty on 200M TVL is an insult. you can make 10x that by exploiting and laundering through tornado. the incentive structure is completely backwards
checks-effects-interactions pattern has been standard since 2016. penpie skipping it on a permissionless registration path is 8 years of security lessons ignored
CEI pattern checks would have caught the Penpie bug in 10 minutes. a 27M protocol skipping basic effects-interactions ordering in 2024 is wild
Penpie lost 27M to the same bug class that killed the DAO in 2016. we have formal verification tools now and teams still ship reentrant code
stack_too_deep_ formal verification exists since 2016 and teams still ship reentrant code in 2024. the tools are there, the discipline isnt
the flash loan plus permissionless market registration combo was brutal. you can audit the reentrancy guard in isolation and it passes. the vulnerability only surfaces when both features interact
Reza M the integration testing angle is key. unit tests pass, individual audits pass, but nobody tests the flash loan plus registration combined path
27M lost to reentrancy in 2024. this bug class has been known since 2016 and teams still ship vulnerable code. the audit culture is genuinely broken
flash_victim_ the real problem is integration testing. individual functions pass audit. flash loan plus permissionless registration combined path creates a vulnerability that only shows up at runtime
formal verification tools exist since 2016 and teams still skip them because deadlines. penpie had 27M in tvl and couldnt run slither. embarassing
reentrancy_ghost_ slither is free and runs in 30 seconds. a protocol with 27M TVL skipping basic static analysis is beyond lazy, its negligent
reentrancy in 2024 is genuinely embarrassing. CEI pattern takes 10 minutes to implement. a 27M protocol couldnt be bothered
Eva J. and the 50k bug bounty on 27M TVL is insulting. white hats get 50k, black hats get 27M. the incentive structure literally rewards exploitation
bounty_gap_ hit the nail. 50k bounty on 27M TVL is not an incentive program its an insult. white hats deserve at least 1 percent of TVL
reentrancy in 2024 with 27M TVL is like leaving your front door open in a neighborhood with daily break-ins. CEI pattern takes 10 minutes to implement. no excuses
Penpie got drained for $27M using the same reentrancy vector from the 2016 DAO hack. 8 years of auditing tooling and people still skip checks-effects-interactions
The flash loan plus permissionless market registration combination was the real innovation in this attack. pure reentrancy doesnt drain $27M without leverage
reentrancy_museum_ exactly. the attacker used flash loans to inflate balances before the reentrant call. classic amplification on top of an old bug