What’s the problem with pipe-curl-into-sh?

11 points by ecco


You’ve seen it : many popular tools will have a one-liner homepage with something along the lines of

curl https://fancy.tool/install.sh | /bin/sh

And inevitably people will comment on how unsafe this is.

I don’t get it. How is it any more unsafe than cloning a repo and building and running its code?

kornel

There is no realistic scenario where this matters, but there was a blog post describing a clever hack based on this.

The cleverness of it makes peoples' imaginations run wild, and harms their sense of security, regardless whether that impacts real-world security or not. Any explanation of why the cleverness doesn't matter only nerdsnipes people into inventing increasingly contrived scenarios where a brilliant attacker could actually pull it off, and then curl | sh ends up being associated with the wildest attacks anyone could imagine.

The hack is that a script may make bash read it slowly, causing backpressure in curl, which the server can detect and serve a different rest of the script than if it was downloaded without being executed. It feels "undetectable" which makes it extra scary. People don't read the source of things they're installing, but they like to think they would. The loss aversion makes losing the mere possibility feel even worse.

The problem with this, apart from -x and VMs existing, is that there's no threat model where this is relevant. Trustworthy sources won't hack you this way, and untrustworthy ones will tell you to use PPA instead, knowing that you'll give it root without even blinking.

strugee

It is very easy to screw up an installer script like this if you don't know what you're doing. Take this script (shebangs omitted for brevity):

echo 'Installing foobar...'
echo "Pretend there's some work done here, call it step 1"
echo "Pretend there's some more/different work done here - step 2"
echo 'Foobar installed.'

Even this simple script is wrong, because the network connection can be aborted before the byte range that has the step 2 command gets to your computer. Now you've run step 1, but not step 2. But we can do even worse, so let's get more specific:

echo 'Cleaning up old versions of foobar...'
rm -rf ~/.local/lib/foobar
echo 'Installing fresh copy of foobar...'
# curl | tar xC ~/.local/lib/ here or something
echo 'Foobar installed'

If the network connection here aborts at the exact right time, whoops! You've run rm -rf ~. You run a full system backup before every time you install a new operating system, repartition your drive... or use curl | sh, right?

The correct way to do this is:

main() {
    echo 'Cleaning up old versions of foobar...'
    # Etc.
}

main

Big projects presumably (maybe!) will get this right. But not everyone will. I have corrected this bug in the installer script of at least one not-obscure project (can't remember which one, or exactly how not-obscure).