Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arbitrary-send-eth false positive #1225

Open
GeraldRyan opened this issue Jun 4, 2022 · 2 comments
Open

Arbitrary-send-eth false positive #1225

GeraldRyan opened this issue Jun 4, 2022 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@GeraldRyan
Copy link

GeraldRyan commented Jun 4, 2022

Describe the issue:

UPDATE:

(2) and (3) are resolved by using detector name "arbitrary-send", not "arbitrary-send-eth". That could be made more clear in the docs since it is titled "Check: arbitrary-send-eth" on the man page, but it has been resolved

However, (1) still seems to be an issue

OP:

arbitrary-send-eth seems broken- both producing false positive (1), and not working as a detector that can be ignored or detected against individually (2) and (3).

    function getPayout(address payable addressOfProposer)
        public
        returns (bool)
    {
        // Get the available allowance first amd store in uint256.
        uint256 allowanceAvailable = _payoutTotals[addressOfProposer];
        require(allowanceAvailable > 0, "You do not have any funds available.");
        _decreasePayout(addressOfProposer, allowanceAvailable);
        
        (bool success,) = addressOfProposer.call{value: allowanceAvailable}("");
        require(success, "Failed to send eth");

        emit Withdraw(addressOfProposer, allowanceAvailable);
        return true;
    }

(1) This code appears controlled, not sending ether to an arbitrary user address. They have to have an allowanceAvailable per contract state, yet slither produces:


PowDAO.getPayout(address) (PowDAO.sol#142-157) sends eth to arbitrary user
        Dangerous calls:
        - (success) = addressOfProposer.call{value: allowanceAvailable}() (PowDAO.sol#152)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations 

That's the first bug.

(2) Next, I added this line:

        //slither-disable-next-line arbitrary-send-eth
        (bool success,) = addressOfProposer.call{value: allowanceAvailable}("");

It still produces the high level warning

(3) Third, I ran

slither PowDAO.sol --detect arbitrary-send-eth
And I got the response

Traceback (most recent call last):
  File "/home/gerald/.local/bin//slither", line 8, in <module>
    sys.exit(main())
  File "/home/gerald/.local/lib/python3.8/site-packages/slither/__main__.py", line 632, in main
    main_impl(all_detector_classes=detectors, all_printer_classes=printers)
  File "/home/gerald/.local/lib/python3.8/site-packages/slither/__main__.py", line 671, in main_impl
    detector_classes = choose_detectors(args, all_detector_classes)
  File "/home/gerald/.local/lib/python3.8/site-packages/slither/__main__.py", line 211, in choose_detectors
    raise Exception(f"Error: {detector} is not a detector")
Exception: Error: arbitrary-send-eth is not a detector

Code example to reproduce the issue:

    function getPayout(address payable addressOfProposer)
        public
        returns (bool)
    {
        // Get the available allowance first amd store in uint256.
        uint256 allowanceAvailable = _payoutTotals[addressOfProposer];
        require(allowanceAvailable > 0, "You do not have any funds available.");
        _decreasePayout(addressOfProposer, allowanceAvailable);
        //slither-disable-next-line arbitrary-send-eth
        (bool success,) = addressOfProposer.call{value: allowanceAvailable}("");
        require(success, "Failed to send eth");

        emit Withdraw(addressOfProposer, allowanceAvailable);
        return true;
    }

Version:

0.8.3

Relevant log output:

PowDAO.getPayout(address) (PowDAO.sol#142-157) sends eth to arbitrary user
        Dangerous calls:
        - (success) = addressOfProposer.call{value: allowanceAvailable}() (PowDAO.sol#152)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations 

and

slither PowDAO.sol --detect arbitrary-send-eth

Traceback (most recent call last):
  File "/home/gerald/.local/bin//slither", line 8, in <module>
    sys.exit(main())
  File "/home/gerald/.local/lib/python3.8/site-packages/slither/__main__.py", line 632, in main
    main_impl(all_detector_classes=detectors, all_printer_classes=printers)
  File "/home/gerald/.local/lib/python3.8/site-packages/slither/__main__.py", line 671, in main_impl
    detector_classes = choose_detectors(args, all_detector_classes)
  File "/home/gerald/.local/lib/python3.8/site-packages/slither/__main__.py", line 211, in choose_detectors
    raise Exception(f"Error: {detector} is not a detector")
Exception: Error: arbitrary-send-eth is not a detector
@GeraldRyan GeraldRyan added the bug-candidate Bugs reports that are not yet confirmed label Jun 4, 2022
@0xalpharush
Copy link
Contributor

We can look into tightening the heuristics to ignore transfers to addresses where the amount sent is based on the address i.e. used as key in a mapping or argument of a function.

I think the detector in the 0.8.3 is still named "arbitrary-send" and was renamed to "arbitrary-send-eth" on the development branch (#1025), so substituting in "arbitrary-send" should work.

@0xalpharush 0xalpharush changed the title [Bug-Candidate]: Arbitrary-send-eth false positive && 'not a detector' Arbitrary-send-eth false positive Jun 17, 2022
@0xalpharush 0xalpharush added enhancement New feature or request and removed bug-candidate Bugs reports that are not yet confirmed labels Jun 17, 2022
@0xalpharush 0xalpharush self-assigned this Jul 7, 2022
@Otto-AA
Copy link

Otto-AA commented Dec 2, 2023

We can look into tightening the heuristics to ignore transfers to addresses where the amount sent is based on the address i.e. used as key in a mapping or argument of a function.

From my understanding, the detector already tries to exclude functions where the address is used as an index (eg uint256 allowanceAvailable = _payoutTotals[addressOfProposer];). Here is the code that seems to check for this:

if isinstance(ir, Index):
if ir.variable_right == SolidityVariableComposed("msg.sender"):
return False
if is_dependent(
ir.variable_right,
SolidityVariableComposed("msg.sender"),
deps_target,
):
return False

However, this only checks for msg.sender, while later on is_tainted also checks for function inputs, tx.origin and more. The solution is likely to check if a tainted value is used as an index, rather than only checking if a variable depending on msg.sender is used as an index.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants