curl | bash and the Slow Death of “Did You Read It?”

Want clean code, better do the review…
Been chewing on this one for a while. Every time I see another “just run this to install” one-liner I get the same itch I got the day AT&T handed me a “did you mean” page off my own DNS queries. That feeling of, wait, when did I agree to this?
So let me say the quiet parts out loud.
We have, as an industry, decided that reading the software we install is somebody else’s job. Usually nobody’s.
We have, as an industry, decided that moving slow enough to have a secure posture is the fiscal equivalent of taking a dirt nap.
We have, as an industry, decided to tell people to turn off the security if it gets in the way.
How we got here
I have been installing software on machines since before there was a public internet to download it from. We typed it in from magazines. We traded it on disk. And yeah, plenty of it was garbage, but the chain was short. You could see the whole thing. You knew where the code came from because you were holding it.
Now the install story for a shocking amount of modern tooling is this:
curl -fsSL https://example.com/install.sh | bashPipe a script you have never read, from a server you do not control, straight into a shell. No pause. No diff. No “here is what I am about to do to your system.” And once that script runs, odds are good its real job is to go fetch a package manager and pull down a tree of dependencies. Which pull their own dependencies. Which pull their own.
Nobody reads them. I mean nobody. Not you, not me, not the maintainer who took the dependency, not the CI pipeline that runs the whole thing fresh on every build. We are lucky if the entire thing has passed linting let alone a security review. If more than 1 in 10,000 users presented with a PKGBUILD in a day actually read it I would be shocked.
We have built a tower of trust where every floor is just assuming the floor below it did the checking.
It did not.
This is not hypothetical, and it is not rare anymore
Two things landed recently that should have made more people nervous than they did.
First, the AUR. In June 2026 someone impersonated a trusted Arch maintainer, adopted over 400 abandoned packages, and slipped in a preinstall step. And here is the part that ties the whole knot together: that PKGBUILD reached out and used npm to install a package called atomic-lockfile, which was the actual payload. Later waves used Bun to pull a thing called js-digest. We are talking infostealer behavior plus an eBPF rootkit, the kind that hides PIDs and inodes from you so you cannot even see what is running. The maintainers cleaned it up, and one of them flatly called the cleanup “whack-a-mole.” A user on the thread said they had never been so glad they go months without updating their AUR packages. Sit with that. The safety move was not keeping current.
Second, npm. Around the same time, Microsoft documented a campaign of 33 malicious npm packages using dependency confusion: register a public package under a name that mirrors some company’s internal one, give it an absurd version number like 100.100.100 so it wins resolution, and wait for a misconfigured install to grab yours instead of the real one. The malicious code ran from a postinstall hook. Not when you require() it. Not when you run it. The moment you typed npm install. It fingerprinted the environment, checked whether it was sitting in CI so it could go quiet and dodge the security tooling, then phoned home. And it was built in two phases on purpose: just look around now, flip a flag on the server later, come back and rob the place once they know which boxes are worth robbing.
Same shape both times. Trusted-looking name, automatic execution at install, a dependency nobody opened, a payload nobody saw.
And when you raise your hand about it
Here is the part that really abrades me.
Bring this up in a distro support channel and watch what happens. First pass, you get waved off. “It’s fine.” “Just use the AUR, everybody does.” “That’s not really a supported repo anyway.” Cool, great, very reassuring.
Then something breaks, or something bites you, and you come back. Now the script flips. Now it is “well, why didn’t you read the PKGBUILD?” “Why didn’t you audit the install script?” “You’re supposed to review what you install.”
You cannot have it both ways. You do not get to tell people the convenient path is fine when they are nervous and then tell them they were negligent when it blows up. That is not a security culture. That is blame laundering. You pushed the easy button as the answer, and you kept the “you should have known better” card in your back pocket for when the easy button misfired.
If reviewing every PKGBUILD and every transitive dependency were actually reasonable, the convenient path would not exist, because everyone would be too busy reading. The whole appeal of “just use the AUR” is that you don’t. Pretending otherwise after the fact is just covering.
The distros are not innocent here either
I want to be fair, because the maintainers who cleaned up that AUR mess worked their tails off and I respect it. But the ecosystem they are defending is a mess of our own making, and a lot of that mess is the refusal to just pick a lane.
Look at the state of a modern mainstream distro. Ubuntu 26.04 ships with, what, three ways to install a thing(I mean they have a custom dialog that tries to guide you to the right app for the right use)? apt, snap, and flatpak all sitting there, each with its own trust model, its own update path, its own sandbox story, its own failure modes. Half the time you do not even know which one apt install is going to hand you anymore, because it might quietly route you to a snap.
That is the enshittification of the thing I have trusted my whole career. Not one curated, validated, tested path. Three overlapping ones, layered on top of each other, none of them fully responsible for the others. Every extra layer is another seam, and every seam is another place for someone to slip something in.
Complexity is not a neutral cost. Complexity is attack surface wearing a hoodie.
When you cannot tell a user a simple true sentence about where their software came from and who checked it, you have already lost the security argument. You just haven’t been billed for it yet.
And then there is AppImage
I have to single this one out, because AppImage is where the whole philosophy curdles into something almost funny if it were not so dangerous.
The pitch is beautiful. One file. No install. No dependency hunting. Download it, chmod +x, double-click, done. And I get the appeal, I really do. I have spent enough of my life chasing missing libraries to understand why “just give me one file that runs” sounds like heaven.
Except it does not run. Not on a modern Ubuntu, anyway. Pull up any “why won’t my AppImage start” guide written in the last year and you will find the same parade: the FUSE 2 library got dropped so you have to go install libfuse2t64 by hand, the browser stripped the execute bit, the GLIBC version does not match, and Ubuntu 24.04 locked down unprivileged user namespaces so the bundled Chromium sandbox in every Electron app face-plants on startup.
And here is the punchline. The number one “fix” you will find for that last one, recommended freely, casually, all over the place, is to launch the thing with
--no-sandbox
Read that again.
The advice for a security feature getting in your way is to turn off the security feature.
Why does this happen? Partly because AppArmor, for all that it is doing the right thing here, is terrible at telling you that it did what it did. You get a Failed to move to new namespace: Operation not permitted and nothing else. No “I blocked this.” No “here is the profile that did it.” No “here is the narrow, scoped way to allow just this one app.” So the tired human at the keyboard does the thing that makes the error go away, and --no-sandbox makes the error go away. The secure path, writing a targeted AppArmor profile that grants just userns to just that one binary, exists, but you have to already know it exists, and the tooling does nothing to walk you there. So nobody does it.
A security boundary that cannot explain itself trains people to disable it. Every single time.
If this were only about my home lab, I would grumble and move on. I have rebuilt boxes before. I will again.
But look at where we are pointing all of this. We are not just installing chat clients and text editors this way. We are wiring these same casually-assembled dependency trees into automation that touches production, into CI that holds the keys to everything, into agents and AI tooling that we are increasingly handing real control. Control over deployments. Over infrastructure. Over decisions that used to need a human with a finger on the button.
Think about that npm payload that checked whether it was in CI so it could stay quiet. Now imagine that same install-time foothold sitting inside the pipeline that an AI agent uses to ship code, or rotate credentials, or stand up infrastructure. The recon-now-exploit-later design is not a coincidence. That is somebody being patient, mapping the high-value targets, waiting for the day the flag flips.
We are speed-running the integration of these tools into the load-bearing parts of our lives, and the foundation under them is “curl it and hope.” The blast radius is not your laptop anymore. It is everything the automation can reach. And the automation can reach a lot.
What I actually do
I do not claim to be the smartest person in any room, and I would genuinely like someone to tell me where I am wrong on this. But here is where I have landed for my own setup:
If I would not paste a stranger’s command into my root shell, I do not pipe their script into it either. Same thing. Download it, read it, then run it. If its new or you aren’t certain, spin up a VM and run it in that. Yes it is slower. That is the point. Stick to the validated, signed, official repo when one exists. The boring path is boring because someone already did the worrying for you. For npm and friends, I turn off install scripts by default (npm config set ignore-scripts true) and pin versions. If a package genuinely needs a postinstall hook to function, I want to know why before it runs, not after. I treat anything that “just works” with one magic line as a thing I have not actually inspected. Because I haven’t.
None of that is bulletproof. A determined supply-chain attack can still get you, and I am not going to pretend otherwise. But “I read it first” is the one defense that scales down to a single tired admin at 11pm, and right now we are actively teaching people to skip it.
This is not one platform’s problem
Before anyone reaches for the “well that’s just Linux” or “that’s just an npm thing” defense, no. Every major platform has its own flavor of “run this thing nobody read,” and every one of them has been used in a real attack. Here is a rundown of installers, package managers, and environment tools that have been turned into delivery trucks, specifically because the script in the middle is one nobody opens.
▹ xz / liblzma (CVE-2024–3094) — Linux. A maintainer spent two years building trust on an open-source compression library, then slipped obfuscated build-time code into the release tarballs of 5.6.0 and 5.6.1. The malicious bit lived in the build scripts, not the source you would read on the repo, and it targeted SSH. It rated a CVSS 10 and was caught almost by accident by one engineer wondering why his logins were 500ms slow. Nobody reviews the autotools glue in a tarball. That was the whole point.
▹ AUR — 400+ packages (June 2026) — Linux/Arch. Covered above. Someone impersonated a trusted maintainer, adopted hundreds of abandoned packages, and added a preinstall step that called npm (and later Bun) to pull the actual payload. PKGBUILDs and install scripts that the AUR model explicitly expects you to read, and that nobody does.
▹ npm dependency-confusion campaign (May 2026) — cross-platform. Dozens of malicious packages published under names mirroring companies’ internal ones, with version numbers cranked absurdly high to win resolution. The payload ran from a postinstall hook the instant you typed npm install, fingerprinted the box, went quiet if it detected CI, and was built to come back later. Windows, macOS, Linux, anywhere Node runs.
▹ litellm on PyPI (March 2026) — cross-platform. A poisoned release (versions 1.82.7 and 1.82.8) shipped a .pth file, which Python executes automatically on interpreter startup, no import required. So the credential stealer ran the moment any Python process started on the machine, scraping SSH keys and cloud creds and shipping them off to an attacker server. And the part that should land for anyone reading the rest of this post: litellm is an LLM gateway, the thing that holds every model-provider API key in an org. Worse, the attackers got the publishing token in the first place by way of a different compromised tool in litellm’s own CI pipeline. Turtles all the way down. .pth files are exactly the kind of plumbing nobody audits in a dependency.
▹ 3CX Desktop App (2023) — Windows and macOS. A signed, trusted softphone app used by a reported 600,000 organizations shipped trojanized installers, a .msi for Windows and a .dmg for Mac, through the official update channel. The build environments themselves were compromised, and the way the attackers got in was its own supply-chain attack: a 3CX employee had installed a trojanized copy of an unrelated piece of trading software. Investigators called it the first publicly reported case of one supply-chain compromise cascading into another. The installer everyone trusted and ran without a second thought carried a backdoor. You cannot “read” an MSI, and almost nobody verifies what an update actually does.
▹ Fake Homebrew / ClickFix malvertising (2024–2025) — macOS and Linux. Attackers bought Google ads displaying the real brew.sh URL, then redirected to a near-identical clone that handed you a curl | bash one-liner, the exact same install ritual the real Homebrew uses. Paste it into Terminal and you got AMOS infostealer instead of a package manager. Some variants hid a base64 command behind a fake “verification” copy button. This one is pure social engineering riding on a habit we taught everyone was normal. That is the part that should sting.
Six different ecosystems. Six different file types. One identical root cause: a script or artifact in the middle of the chain that the design assumes someone will inspect, and that in practice nobody ever does.
We optimized the friction out of installing software. Turns out the friction was load-bearing.
Read your install scripts. Update, but, don’t be the first person to update, unless its fixing a critical vulnerability for YOU. Give it a few hours or a day maybe.
Peace out.
References
I do not claim this list is exhaustive, and I am sure I have missed events worth including. Correct me if I got something wrong. Two sources max per event, originals where I could find them.
xz / liblzma backdoor (CVE-2024–3094)
- CISA advisory: https://www.cisa.gov/news-events/alerts/2024/03/29/reported-supply-chain-compromise-affecting-xz-utils-data-compression-library-cve-2024-3094
- Palo Alto Unit 42 threat brief: https://unit42.paloaltonetworks.com/threat-brief-xz-utils-cve-2024-3094/
AUR 400+ compromised packages (June 2026)
- Arch Linux official news: https://archlinux.org/news/active-aur-malicious-packages-incident/
- IFIN threat-intel writeup: https://discourse.ifin.network/t/400-aur-packages-compromised-with-infostealer-and-rootkit/577
npm dependency-confusion campaign (May 2026)
- Microsoft Security blog: https://www.microsoft.com/en-us/security/blog/2026/05/29/33-malicious-npm-packages-abuse-dependency-confusion-profile-developer-environments/
litellm PyPI compromise (.pth startup execution)
- Trend Micro security alert: https://success.trendmicro.com/en-US/solution/KA-0022880
3CX Desktop App (2023)
- CISA alert: https://www.cisa.gov/news-events/alerts/2023/03/30/supply-chain-attack-against-3cxdesktopapp
- Bitdefender technical advisory: https://www.bitdefender.com/en-us/blog/businessinsights/technical-advisory-software-supply-chain-attack-against-3cx-desktop-app
Fake Homebrew / ClickFix malvertising (2024–2025)
- BleepingComputer: https://www.bleepingcomputer.com/news/security/google-ads-for-fake-homebrew-logmein-sites-push-infostealers/
- SecurityWeek: https://www.securityweek.com/homebrew-macos-users-targeted-with-information-stealer-malware/
AppImage / Ubuntu sandbox breakage
- “How to Fix AppImage Not Working on Ubuntu Desktop (2026)”: https://cloudhousetechnologies.com/blog/how-to-fix-appimage-not-working-on-ubuntu-desktop-2026
This story was originally posted on my Medium account, drahcir_rahl — read the original: curl | bash and the Slow Death of “Did You Read It?”.