root

pages table of contents

Using curl | bash safely

The post you're about to read is the result of the research of [REDACTED] foxes in a trenchcoat. I don't know what I'm doing.

Take everything I say here with a wheelbarrow of salt. Do your own research. Don't trust one person's opinion with the security your infrastructure.

In April of 2024 I wrote a post on Fedi explaining that using curl | bash was not a security risk. I based my original argument on the fact that you ultimately have to trust the person that provides you the code. A bit later, I discussed on the same topic with 2 people in a Matrix channel. They exposed me to an attack vector that makes using curl | bash actually potentially dangerous. This caused me to do further research on the topic, and ultimately write this post.

TL;DR: If you're here because you just want to download software, go for it. You're probably going to be just fine. If you're interested in information security or want to implement a curl | bash script however, please read the rest.

Terminology

Attack surface

We can establish a simplified supply chain for a software artifact:

/----------\         /--------\         /--------\
| Artifact | ------> | Server | ------> | Client |
\----------/    |    \--------/    |    \--------/
    (1)        (2)      (3)       (4)      (5)

An malicious actor could compromise the supply chain by attacking:

  1. The machine the artifact is built on;
  2. The connection beteen the artifact builder and the server;
  3. The machine the server is served to client by;
  4. The connection beteen the server and the client;
  5. The client that requests the artifact.

For the purpose of this post however, the attack vectors (1), (2) and (5) are out of scope, which leaves us with only (3) and (4).

There's not a lot that can be leveraged then ? So I'd imagine using curl | bash is safe most of the time.

Precisely. Most of the time.

An example script

We'll use this script as an example for the rest of this post:

curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

This script installs the Determinate Nix installer, an alternative installer for the Nix package manager. Let's break it down a bit:

We can see that the script explicitly requires curl to use a secure connection. At first glance, this seeems like a secure way to run the installer. However, this script does't check that the script you're downloading is what it should be. If the server is compromised in some way, we could be downloading malware instead.

Securing our infrastructure

We can mitigate this risk by using a method used by most package managers, which is using 2 different servers with different functions:

This way, if either server is compromised, the software that's served to the client will not be verified and therefore not run.

We can drastically reduce the risk of getting both machines compromised at once by:

This way, the only thing we have to trust is that the artifacts uploaded to the servers are healthy, and that both servers are not compromised at once (which should be overwhelmely unlikely if they are separate and different enough).

Now, our infrastructure looks like this:

                    /-----------\
                    |  Signing  |
                /-> | authority | --\
/----------\    |   \-----------/    \---> /--------\
| Artifact | ---|                          | Client |
\----------/    |   /-----------\    /---> \--------/
                \-> | Artifact  | --/
                    | provider  |
                    \-----------/

There are still other parameters that I won't bother bringing into the picture right now, like the SSL certificates provider, and of course, the way the servers get the artifact in the first place (which depends on how your script is written and how and where your software is built).

An example infrastructure would look like this:

TODO

- Domain: `gitea.com`

Notice the artifact is now in a different domain (install-determinate.systems) and not in a subdomain like it was previously (install.determinate.systems). That means that both servers need to use 2 very different SSL certificates.

Now, compromising this part of the supply chain has become extremely hard. The attacker will either:

Now, it would be a lot more feasible to attack another part of the supply chain, which is a subject for another post.

Implementing curl | bash safely

You've spent so much time explaining that curl | bash is insecure, why would we bother making a secure version of it ?

Because the other way around this is to package your software for every distro and package manager under the sun, which is a task which simply imagining sends shivers down my spine.

Making a shell script that leverages this infrastructure isn't actually that hard. Most of the work is around creating two resilient and independent servers. What we have to do is simply to check the artifact provider's response against a hash or a signature provided by the signing authority.

# good script
CURL=$(curl --tlsv1.3 https://pastebin.com/raw/Tity9gDQ)
# bad script
# CURL=$(curl --tlsv1.3 https://pastebin.com/raw/xYTmzaMQ)

EXPECTED='caa42ef74ba42d3d097bfcd7c718cd22ca807c1116ce1f86b00ecce9337858d7  -'
ACTUAL=$(echo $CURL | sha256sum)

if [ "$EXPECTED" == "$ACTUAL" ]; then
  echo $CURL | bash
else
  echo "Checksum mismatch"
fi

This can be minified a bit, but it's more readable like that.

Updating the script

When a new artifact is available, the artifact provider has to start hosting it. Then, the signing authority needs to get the artifact's hash (dirctly from the source) and then update the way the script is displayed (git repo or website).

Preferably, the artifact provided should include the artifact's version in it's URL and keep hosting non-vulnerable versions, that way the script will still work before the signing authority finishes its work, and after another update is released.

Fediring

tilde.club webring

the no ai webring


cool people and creatures
xeiaso badge tea badge maia badge vulpinecitrus badge elke badge byte badge rail badge sammy badge soatok badge freeplay badge
misc
fediring badge kitsulife badge nixos badge tilde.club badge tilde.club badge enby badge iso8601 badge no fkn thanks badge made with my own two paws badge vscodium badge creativecommons badge
written by human, not by ai this website is a work in progress

memetic apiopage | buttons credits | warrant canary


copyright notice: This webite's source code and built webpages when shared in their entirety are provided under the GPL-3.0 license. All blog posts, articles and Markdown files contained within the git repository are shared under the CC BY-NC-SA 4.0 license. If you want to use my content for commercial purposes, feel free to contact me.

This is an actual website. Read the web0 manifesto.

This page is cleaner than 0% of all web pages globally according to websitecarbon.com.

Built by mkdocs and served by tilde.club.

rss feed: todo - email me if you want to subscribe !


This website does not use JavaScript or other tracking technologies.

Last update: 2024-08-24