We just can't trust dependencies and dev setups. I wanted to say "anymore" but we never could. Dev containers were never good enough, too clumsy and too little isolation. We need to start working in full sandboxes with defence in depth that have real guardrails and UIs like vm isolation + container primitives and allow lists, egress filters, seccomp, gvisor and more but with much better usability. Its the same requirements we have for agent runtimes, lets use this momentum to make our dev environments safer! In such an environment the container would crash, we see the violations, delete it and dont' have to worry about it. We should treat this as an everyday possibility not as an isolated security incident.
This is the security shortcuts of the past 50 years coming back to bite us. Software has historically been a world where we all just trust each other. I think that’s coming to an end very soon.
We need sandboxing for sure, but it’s much bigger than that. Entire security models need to be rethought.
This assumes that we can get a locked down, secure, stable bedrock system and sandbox that basically never changes except for tiny security updates that can be carefully inspected by many independent parties.
Which sounds great, but the way things work now tend to be the exact opposite of that, so there will be no trustable platform to run the untrusted code in. If the sandbox, or the operating system the sandbox runs in, will get breaking changes and force everyone to always be on a recent release (or worse, track main branch) then that will still be a huge supply chain risk in itself.
The secure boot "shim" is a project like this. Perhaps we need more core projects that can be simple and small enough to reach a "finished" state where they are unlikely to need future upgrades for any reason. Formal verification could help with this ... maybe.
> This assumes that we can get a locked down, secure, stable bedrock system and sandbox that basically never changes except for tiny security updates that can be carefully inspected by many independent parties.
For the most part you can. Just version pin slightly-stale versions of dependencies, after ensuring there are no known exploits for that version. Avoid the latest updates whenever possible. And keep aware of security updates, and affected versions.
Don't just update every time the dependency project updates. Update specifically for security issues, new features, and specific performance benefits. And even then avoid the latest version when possible.
Sure, and that is basically what sane people do now, but that only works until something needs a security patch that was not provided for the old version, and changing one dependency is likely to cascade so now I am open to supply chain attacks in many dependencies again (even if briefly).
To really run code without trust would need something more like a microkernel that is the only thing in my system I have to trust, and everything running on top of that is forced to behave and isolated from everything else. Ideally a kernel so small and popular and rarely modified that it can be well tested and trusted.
Virtual machines are that - tiny surfaces to access the host system (block disk device, ...). Which is why virtual machine escape vulnerabilities are quite rare.
>Which sounds great, but the way things work now tend to be the exact opposite of that, so there will be no trustable platform to run the untrusted code in.
This is the problem with software progressivism. Some things really should just be what they are, you fix bugs and security issues and you don't constantly add features. Instead everyone is trying to make everything have every feature. Constantly fiddling around in the guts of stuff and constantly adding new bugs and security problems.
I think Bootstrappable Builds from source without any binaries, plus distributed code audits would do a better job than locking down already existing binaries.
> This assumes that we can get a locked down, secure, stable bedrock system and sandbox that basically never changes except for tiny security updates that can be carefully inspected by many independent parties.
Not really.
You should limit the attack surface for third-party code.
A linter running in `dir1` should not access anything outside `dir1`.
The NIH syndrome becoming best practice (a commenter below already says they "vibe-coded replacements for many dependencies") would also save quite a few jobs, I suspect. Fun times.
I've been thinking the same thing. And it's somewhat parallel to what happened to meditation vs. drugs. In the old world the dangerous insights required so many years of discipline that you could sort of trust that the person getting the insight would be ok. But then any idiot can get the insight by just eating some shrooms and oops, that's a problem. Mostly self-harm problem in that case. But the dynamic is somewhat similar to what's happening now with LLMs and coding.
Software people could (mostly) trust each other's OSS contributions because we could trust the discipline it took in the first place. Not any more.
In the old world the dangerous insights required so many years of discipline that you could sort of trust that the person getting the insight would be ok. But then any idiot can get the insight by just eating some shrooms and oops, that's a problem.
I would think humans have been using psychedelics since before we figured out meditation. Likely even before we were humans.
What we need is accountability and ties to real-world identity.
If you're compromised, you're burned forever in the ledger. It's the only way a trust model can work.
The threat of being forever tainted is enough to make people more cautious, and attackers will have no way to pull off attacks unless they steal identities of powerful nodes.
Like, it shouldn't be a thing that some large open-source project has some 4th layer nested dependency made by some anonymous developer with 10 stars on Github.
If instead, the dependency chain had to be tied to real verified actors, you know there's something at stake for them to be malicious. It makes attacks much less likely. There's repercussions, reputation damage, etc.
> The threat of being forever tainted is enough to make people more cautious
No it's not. The blame game was very popular in the Eastern Block and it resulted in a stagnant society where lots of things went wrong anyway. For instance, Chernobyl.
> What we need is accountability and ties to real-world identity.
Who's gonna enforce that?
> If you're compromised, you're burned forever in the ledger.
Guess we can't use XZ utils anymore cause Lasse Collin got pwned.
Also can't use Chalk, debug, ansi-styles, strip-ansi, supports-color, color-convert and others due to Josh Junon also ending up a victim.
Same with ua-parser-js and Faisal Salman.
Same with event-stream and Dominic Tarr.
Same with the 2018 ESLint hack.
Same with everyone affected by Shai-Hulud.
Hell, at that point some might go out of their way to get people they don't like burned.
At the same time, I think that stopping reliance on package managers that move fast and break things and instead making OS maintainers review every package and include them in distros would make more sense. Of course, that might also be absolutely insane (that's how you get an ecosystem that's from 2 months to 2 years behind the upstream packages) and take 10x more work, but with all of these compromises, I'd probably take that and old packages with security patches, instead of pulling random shit with npm or pip or whatever.
Though having some sort of a ledger of bad actors (instead of people who just fuck up) might also be nice, if a bit impossible to create - because in the current day world that's potentially every person that you don't know and can't validate is actually sending you patches (instead of someone impersonating them), or anyone with motivations that aren't clear to you, especially in the case of various "helpful" Jia Tans.
Accountability is on the people using a billion third party dependencies, you need to take responsibility for every line of code you use in your project.
If you are really talking about dependencies, I’m not sure you’ve really thought this all the way through. Are you inspecting every line of the Python interpreter and its dependencies before running? Are you reading the compiler that built the Python interpreter?
It's still smart to limit the amount of code (and coders) you have to trust. A large project like Python should be making sure it's dependencies are safe before each release. In our own projects we'd probably be better off taking just the code we need from a library, verifying it (at least to the extent of looking for something as suspect as a random block of base64 encoded data) and copying it into our projects directly rather than adding a ton of external dependencies and every last one of the dependencies they pull in and then just hoping that nobody anywhere in that chain gets compromised.
Would you drive on bridges or ride in elevators "inspected" by anons? Why are our standards for digital infrastructure and software "engineering" so low?
I don't blame the anons but the people blindly pulling in anon dependencies. The anons don't owe us anything.
This option is available already in the form of closed-source proprietary software.
If someone wants a package manager where all projects mandate verifiable ID that's fine, but I don't see that getting many contributors. And I also don't see that stopping people using fraudulent IDs.
There is no need of that bullshit. Guix can just set an isolated container in seconds not touching your $HOME at all and importing all the Python/NPM/Whatever dependencies in the spot.
"Anymore" is right though. This should be a call to change the global mindset regarding dependencies. We have to realize that the "good ol days" are behind us in order to take action.
Otherwise people will naysay and detract from the cause. "It worked before" they will say. "Why don't we do it like before?"
DISA STIG already forbids use of the EPEL for Red Hat Enterprise Linux. Enterprise software install instructions are littered with commands to turn off gpgcheck and install rpm's from sourceforge. The times are changing and we need cryptographically verifiable guarantees of safety!
I would split the agent loop totally from the main project of tightbeam, no one wants yet another new agent harness we need to focus on the operational problems. Airlock seems interesting in theory but its really hard to believe this could capture every single behaviour of the native local binaries, we need the native tools with native behaviour otherwise might as well use something like MCP. I would bet more on a git protocol proxy and native solutions for each of these.
Good points across the board. I ran into a lot of problems auditing the security of my approach and it was just too easy to circumvent.
First lesson was that the architecture had to be secure in structure, not configuration. Otherwise, a novice will run claude code on the host machine and just bork the entire setup.
So now I've replaced tightbeam runtime with a small runtime on the workspace container. Tightbeam and Airlock have been moved to separate pods. So you don't need network egress on the workspace pod at all.
Secondly, I'm isolating credentials on Tightbeam and Airlock with k8s jobs. Rather than airlock full CLI commands, you just create "airlock tools" with k8s secrets. Airlock controller never sees the secret. The tool could be like "git-create-branch" and "gh-create-pr".
Tightbeam is pretty much symmetrical. LLM credentials are tied to jobs.
I'm tying them together into a unified architecture now. Please do let me know if you have additional thoughts!
So... I'm working on an open source technology to make a literal virtual machine shippable i.e. freezing everything inside it, isolated due to vm/hypervisor for sandboxing, with support for containers too since it's a real linux vm.
The problems you mentioned resonated a lot with me and why I'm building it, any interest in working to solve that together?: https://github.com/smol-machines/smolvm
Thanks for the pointer! Love the premise project. Just a few notes:
- a security focused project should NOT default to train people installing by piping to bash. If i try previewing the install script in the browser it forces download instead of showing as plain text. The first thing i see is an argument
# --prefix DIR Install to DIR (default: ~/.smolvm)
that later in the script is rm -rf deleting a lib folder. So if i accidentally pick a folder with ANY lib folder this will be deleted.
- Im not sure what the comparison to colima with krunkit machines is except you don't use vm images but how this works or how it is better is not 100% clear
- Just a minor thing but people don't have much attention and i just saw aws and fly.io in the description and nearly closed the project. it needs to be simpler to see this is a local sandbox with libkrun NOT a wrapper for a remote sandbox like so many of the projects out there.
Will try reaching you on some channel, would love to collaborate especially on devX, i would be very interested in something more reliable and bit more lightweight in placce of colima when libkrun can fully replace vz
Love this feedback, agree with you completely on all of it - I'll be making those changes.
1. In comparison with colima with krunkit, I ship smolvm with custom built kernel + rootfs, with a focus on the virtual machine as opposed to running containers (though I enable running containers inside it).
What is the alternative to bash piping? If you don't trust the project install script, why would you trust the project itself? You can put malware in either.
That assumes you even need an install script. 90% of install scripts just check the platform and make the binary executable and put it in the right place. Just give me links to a github release page with immutable releases enabled and pure binaries. I download the binary but it in a temporary folder, run it with a seatbelt profile that logs what it does. Binaries should "just run" and at most access one folder in a place they show you and that is configurable! Fuck installers.
It turns out that it's possible for the server to detect whether it is running via "| bash" or if it's just being downloaded. Inspecting it via download and then running that specific download is safer than sending it directly to bash, even if you download it and inspect it before redownloading it and piping it to a shell.
The server can also put malware in the .tar.gz. Are you really checking all the files in there, even the binaries? If you don't what's the point of checking only the install script?
The latest Firefox build that Debian did only took just over one hour on amd64/armhf and 1.5 hours on ppc64el, the slowest Debian architecture is riscv64 and the last successful build there took only 17.5h, so definitely not days. Your average modern developer-class laptop is going to take a lot less than riscv64 too.
> If you don't what's the point of checking only the install script?
The .tar.gz can be checksummed and saved (to be sure later on that you install the same .tar.gz and to be sure it's still got the same checksum). Piping to Bash in one go not so much. Once you intercept the .tar.gz, you can both reproduce the exploit if there's any (it's too late for the exploit to hide: you've got the .tar.gz and you may have saved it already to an append-only system, for example) and you can verify the checksum of the .tar.gz with other people.
The point of doing all these verifications is not only to not get an exploit: it's also to be able to reproduce an exploit if there's one.
There's a reason, say, packages in Debian are nearly all both reproducible and signed.
And there's a reason they're not shipped with piping to bash.
Other projects shall offer an install script that downloads a file but verifies its checksum. That's the case of the Clojure installer for example: if verifies the .jar. Now I know what you're going to say: "but the .jar could be backdoored if the site got hacked, for both the checksum in the script and the .jar could have been modified". Yes. But it's also signed with GPG. And I do religiously verify that the "file inside the script" does have a valid signature when it has one. And if suddenly the signing key changed, this rings alarms bells.
Why settle for the lowest common denominator security-wise? Because Anthropic (I pay my subscription btw) gives a very bad example and relies entirety on the security of its website and pipes to Bash? This is high-level suckage. A company should know better and should sign the files it ships and not encourage lame practices.
Once again: all these projects that suck security-wise are systematically built on the shoulders of giants (like Debian) who know what they're doing and who are taking security seriously.
This "malware exists so piping to bash is cromulent" mindset really needs to die. That mentality is the reason we get major security exploits daily.
> And I do religiously verify that the "file inside the script" does have a valid signature when it has one.
If you want to go down this route, there is no need to reinvent the wheel. You can add custom repositories to apt/..., you only need to do this once and verify the repo key, and then you get this automatic verification and installation infrastructure. Of course, not every project has one.
Probably on the side of your project, but did you try SmolBSD? <https://smolbsd.org>
It's a meta-OS for microVMs that boots in 10–15 ms.
It can be dedicated to a single service (or a full OS), runs a real BSD kernel, and provides strong isolation.
Overall, it fits into the "VM is the new container" vision.
Disclaimer: I'm following iMil through his twitch streams (the developer of smolBSD and a contributor to NetBSD) and I truly love what he his doing. I haven't actually used smolBSD in production myself since I don't have a need for it (but I participated in his live streams by installing and running his previews), and my answer might be somewhat off-topic.
At a glance, it's a matter of compatibility, most software has first class support for linux. But very interesting work and I'm going to follow it closely
Run locally on macs, much easier to install/use, and designed to be "portable" meaning you can package a VM to preserve statefulness and run it somewhere else.
worked in AWS and specifically with firecracker in the container space for 4 years - we had a very long onboarding doc to dev on firecracker for containers... So I made sure to focus on ease of use here.
Java had that from v1.2 in the 1990s. It got pulled out because nobody used it. The problem of how to make this usable by developers is very hard, although maybe LLMs change the equation.
just sandbox the interpreter (in this case), package manager and binaries.
u can run in chroot jail and it wouldnt have accessed ssh keys outside of the jail...
theres many more similar technologies aleady existing, for decades.
doing it on a per language basis is not ideal. any new language would have to reinvent the wheel.
better to do it at system level. with the already existing tooling.
openbsd has plege/unveil, linux chroot, namespaces, cgroups, freebsd capsicum or w/e. theres many of these things.
(i am not sure how well they play within these scenarios, but just triggering on the sandboxing comment. theres plenty of ways to do it as far as i can tell...)
What if I wanted to write a program that uses untrusted libraries, but also does some very security sensitive stuff? You are probably going to suggest splitting the program into microservices. But that has a lot of problems and makes things slow.
The problem is that programs can be entire systems, so "doing it at the system level" still means that you'd have to build boundaries inside a program.
> Dev containers were never good enough, too clumsy and too little isolation.
I haven't kept up with the recent exploits, so a side question: Have any of the recent supply chain attacks or related exploits included any escapes from basic dev containers?
That's no solution. If you can't trust and/or verify dependencies, and they are malicious, then you have bigger problems than what a sandbox will protect against. Even if it's sandboxed and your host machine is safe, you're presumably still going to use that malicious code in production.
I'm supportive of going further - like restricting what a library is able to do. e.g. if you are using some library to compute a hash, it should not make network calls. Without sub-processes, it would require OS support.
In type system theory I think what you're looking for is "effect systems".
You make the type system statically encode categories of side-effects, so you can tell from the type of a function whether it is pure computation, or if not what other things it might do. Exactly what categories of side-effect are visible this way depends on the type system; some are more expressive than others.
But it means when you use a hash function you can know that it's, eg, only reading memory you gave it access to and doing some pure computation on it.
It's a language/compiler/function call stack feature, not existing as far as I know, but it would be awesome - the caller of a function would specify what resources/syscalls could be made, and anything down the chain would be thusly restricted. The library could try to do its phone home stats and it would fail. Couldn't be C or a C type language runtime, or anything that can call to assembly of course. @compute_only decorator. Maybe could be implemented as a sys-call for a thread - thread_capability_remove(F_NETWORK + F_DISK)? Wouldn't be able to schedule any work on any thread in that case, but Go could have pools of threads for coroutines with varying capabilities. Something to put the developer back in charge of the mountain of dependencies we are all forced to manage now.
That's exactly what a sandbox is designed for. I think you're overly constraining your view of what sort of sandboxing can exist. You can, for example, sandbox code such that it can't do anything but read/write to a specific segment of memory.
Except that LiteLLM probably got pwned because they used Trivy in CI. If Trivy ran in a proper sandbox, the compromised job could not publish a compromised package.
(Yes, they should better configure which CI job has which permissions, but this should be the default or it won't always happen)
> In such an environment the container would crash, we see the violations, delete it and dont' have to worry about it.
This is the interesting part. What kind of UI or other mechanisms would help here? There's no silver bullet for detecting and crashing on "something bad". The adversary can test against your sandbox as well.
Containers can mean many things, if you mean plain docker default configured containers then no, they are a packaging mechanism not safe environment by themselves.
Just because this attack example did not contain container escape exploits does not mean this is safe. Its better than nothing but nothing that will save us.
Those supply chain attacks we are seeing are bad, but if someone burns a 0day container escape for it, it would probably be a net positive effect on security overall. Just saying this is FUD.
Sandboxes yes, but who even added the dependency? Half the projects I see have requirements.txt written by Copilot. AI says "add litellm", dev clicks accept, nobody even pins versions.
Then we talk about containment like anyone actually looked at that dep list.
> We just can't trust dependencies and dev setups.
In one of my vibe coded personal projects (Python and Rust project) I'm actually getting rid of most dependencies and vibe coding replacements that do just what I need. I think that we'll see far fewer dependencies in future projects.
Also, I typically only update dependencies when either an exploit is known in the current version or I need a feature present in a later version - and even then not to the absolute latest version if possible. I do this for all my projects under the many eyes principal. Finding exploits takes time, new updates are riskier than slightly-stale versions.
Though, if I'm filing a bug with a project, I do test and file against the latest version.
> In one of my vibe coded personal projects (Python and Rust project) I'm actually getting rid of most dependencies and vibe coding replacements that do just what I need. I think that we'll see far fewer dependencies in future projects.
No free lunch. LLMs are capable of writing exploitable code and you don’t get notifications (in the eg Dependabot sense, though it has its own problems) without audits.
It might surprise you to learn that a large number of software exploits are written without the attacker having direct access to the program's source code. In fact, shocking as it may seem today, huge numbers of computers running the Windows operating system and Internet Explorer were compromised without the attackers ever having access to the source code of either.
I'm actually curious if the windows source code leak of 2004 increased the number of exploits against windows? I'm not sure if it included internet explorer. I remember that windows 2000 was included back then.
I agree in general, but how are you ever upgrading any of that? Could be a "sleeper compromise" that only activates sometime in the future. Open problem.
A sleeper compromise that cannot execute can still not reach its goal. Generally speaking outdated dependencies without known compromise in a sandbox are still better than the latest deps with or without sandbox.
strongly agree. we keep giving away trust to other entities in order to make our jobs easier. trusting maintainers is still better than trusting a clanker but still risky. We need a sandboxed environment where we can build our software without having to worry about these unreliable factors.
On a personal note, I have been developing and talking to a clanker ( runs inside ) to get my day to day work done. I can have multiple instances of my project using worktrees, have them share some common dependencies and monitor all of them in one place. I plan to opensource this framework soon.
This stuff already exists - mobile phone sandboxed applications with intents (allow Pictures access, ...)
But mention that on HN and watch getting downvoted into oblivion: the war against general computation, walled gardens, locked down against device owners...
You are not being downvoted because the core premise is wrong but because your framing as a choice between being locked out of general purpose computing vs security is repeating the brainwashing companies like apple and meta do to justify their rent-seeking locking out out of competitors and user agency. We have all the tools to build safe systems that don't require up front manifest declaration and app store review by the lord but give tools for control, dials and visibility to the users themselves in the moment. And yes, many of these UIs might look like intent sheets. The difference is who ultimately controls how these Interfaces look and behave.