[HN Gopher] Supply chain attacks are exploiting our assumptions
       ___________________________________________________________________
        
       Supply chain attacks are exploiting our assumptions
        
       Author : crescit_eundo
       Score  : 43 points
       Date   : 2025-11-06 15:46 UTC (7 hours ago)
        
 (HTM) web link (blog.trailofbits.com)
 (TXT) w3m dump (blog.trailofbits.com)
        
       | udev4096 wrote:
       | Instead of securing the "chain", we should instead isolate every
       | library we import and run it under a sandbox. We should adopt the
       | model of QubesOS. It follows security by isolation. There are
       | lots of native sandboxing in linux kernel. Bubblewrap, landlock,
       | gvisor and kata (containers, not native), microVMs, namespaces
       | (user, network), etc
        
         | whytevuhuni wrote:
         | I don't know what the next programming language after Rust will
         | look like, but it will definitely have built-in effects and
         | capabilities.
         | 
         | It won't fix everything (see TARmageddon), but left-pad-rs's
         | build.rs file should definitely not be installing a sudo alias
         | in my .bashrc file that steals my password when I cargo build
         | my project.
        
           | bluGill wrote:
           | I hope you are right, but fear that there is no way to make
           | such a thing that is usable. You likely end up with complex
           | permissions that nobody understands and so you just "accept
           | all", or programs that have things they must do under the
           | same protection as the evil thing you want to block.
        
             | marcosdumay wrote:
             | > but fear that there is no way to make such a thing that
             | is usable
             | 
             | The function declarations declare every action it can do on
             | your system, and any change adding new ones is a breaking
             | change on the library.
             | 
             | We've knew how to do it for ages. What we don't have is a
             | good abstraction to let the compiler check them and
             | transform the actions into high-level ones as they go
             | through the stack.
        
               | bluGill wrote:
               | You end up just declaring you can do anything because
               | every time a function legitimately needs to do something
               | every other function up the chain needs to be updated to
               | do that same thing (even if in practice that can never
               | happen but the compiler can't prove it).
               | 
               | Like you say we don't have a good abstraction for this.
        
               | marcosdumay wrote:
               | > every time a function legitimately needs to do
               | something
               | 
               | Hopefully, you know exactly what a function needs to do
               | when you write it.
               | 
               | > every other function up the chain needs to be updated
               | 
               | There are types reuse and composition to deal with that.
               | Many languages with advanced type systems do composition
               | badly, but it's still there.
        
           | darrenf wrote:
           | Can't help but think that Perl's tainted mode (which is >
           | 30yrs old) had the right idea, and it's a bit strange how few
           | other languages wanted to follow its example. Quoting
           | `perldoc perlsec`:
           | 
           |  _You may not use data derived from outside your program to
           | affect something else outside your program--at least, not by
           | accident. All command line arguments, environment variables,
           | locale information (see perllocale), results of certain
           | system calls ( "readdir()", "readlink()", the variable of
           | "shmread()", the messages returned by "msgrcv()", the
           | password, gcos and shell fields returned by the "getpwxxx()"
           | calls), and all file input are marked as "tainted". Tainted
           | data may not be used directly or indirectly in any command
           | that invokes a sub-shell, nor in any command that modifies
           | files, directories, or processes, with the following
           | exceptions: [...]_
        
         | yupyupyups wrote:
         | If there is a kernel level feature to throw sections of a
         | process memory into other namespaces then yes, that may work.
         | If you mean running a xen hypervisor for sqlite.so, then no
         | thanks.
        
         | criemen wrote:
         | > we should instead isolate every library we import and run it
         | under a sandbox
         | 
         | I don't see how that'd be possible. Often we want the library
         | to do useful things for the application, in the context of the
         | application. What would incentivize developers to specify more
         | fine-grained permissions per library than the union of
         | everything their application requires?
         | 
         | I see more use in sandboxing entire applications, and giving
         | them more selective access than "the entire user account" like
         | we do these days. This is maybe more how smartphones operating
         | systems work than desktop computers?
        
           | immibis wrote:
           | In languages without ambient I/O capabilities, it's not as
           | hard as it sounds if you're used to languages with them.
           | Suppose the only way you can write a file is if I give you a
           | handle to that file - then I know you aren't going to write
           | any other files. Of course, main() receives a handle from the
           | OS to do everything.
           | 
           | If I want you to decode a JPEG, I pass you an input stream
           | handle and you return an output memory buffer; because I
           | didn't give you any other capabilities I know you can't do
           | anything else. Apart from looping forever, presumably.
           | 
           | It still requires substantial discipline because the easiest
           | way to write anything in this hypothetical language is to
           | pass the do-everything handle to every function.
           | 
           | See also the WUFFS project: https://github.com/google/wuffs -
           | where things like I/O simply do not exist in the language,
           | and therefore, any WUFFS library is trustworthy. However,
           | it's not a general-purpose language - it's designed for file
           | format parsers only.
        
             | criemen wrote:
             | Fair enough, it makes more sense in a, say, Haskell-style
             | pure functional language. Instead of getting a general IO
             | monad, you pass in more restricted functionality.
             | 
             | Still, it'd be highly painful. Would it be worth the trade-
             | off to prevent supply chain attacks?
        
         | cesarb wrote:
         | > Instead of securing the "chain", we should instead isolate
         | every library we import and run it under a sandbox.
         | 
         | Didn't we have something like that in Java more than a decade
         | ago? IIRC, you could, for instance, restrict which classes
         | could do things like opening a file or talking to the network.
         | 
         | It didn't quite work, and was abandoned. Turns out it's hard to
         | sandbox a library; the exposed surface ended up being too
         | large, and there were plenty of sandbox escapes.
         | 
         | > There are lots of native sandboxing in linux kernel.
         | Bubblewrap, landlock, gvisor and kata (containers, not native),
         | microVMs, namespaces (user, network), etc
         | 
         | What all of these have in common, is that they isolate
         | processes, not libraries. If you could isolate each library in
         | a separate process, without killing performance with IPC costs,
         | you could use them; one example is desktop thumbnailers, which
         | parse untrusted data, and can use sandboxes to protect against
         | bugs in the image and video codec libraries they use.
        
         | warkdarrior wrote:
         | One downside of fine-grained sandboxing is the overhead, as
         | each (function) call into a library now has to cross sandbox
         | boundaries.
         | 
         | Even if we assume overhead is magically brought to zero, the
         | real challenge is customizing the permission policy for each
         | sandbox. I add, say, 5 new dependencies to my program, and now
         | I have to review source code of each of those dependencies and
         | determine what permissions their corresponding sandboxes get.
         | The library that connects to a database server? Maybe it also
         | needs filesystem access to cache things. The library that
         | parses JSON buffers? Maybe it also needs network access to
         | download the appropriate JSON schema on the fly. The library
         | that processes payments? Maybe it also needs access to location
         | information to do risk analysis.
         | 
         | Are all developers able to define the right policies for every
         | dependency?
        
           | zzo38computer wrote:
           | I think using proxy capabilities would partially mitigate
           | this issue, and effectively they would work by using
           | interfaces rather than permissions. By itself, it will not
           | do; documentation will also be helpful, as well as deciding
           | what you will need for your specific application (which are
           | helpful even independently of such things as this).
        
         | zzo38computer wrote:
         | It might work if you run the library in a separate process.
         | This will work better on a capability-based system (with proxy
         | capabilities; this would have other benefits as well and not
         | only security) than on Linux, although it might still be
         | possible to implement. An alternative way to implement library
         | sandboxing would be to implement the sandboxing at compile
         | time, which would work on any system and not require a separate
         | process, and has both advantages and disadvantages compared
         | with the other way.
        
       | tharne wrote:
       | This is something I've never totally understood when it comes to
       | Rust's much loved memory safety vs. C's lack of memory safety.
       | When it comes to replacing C code with Rust, aren't we just
       | trading memory risk for supply chain risk?
       | 
       | Maybe one is more important than the other, I don't know. All the
       | languages I use for work or hobbies are garbage collected and I'm
       | not a security professional. But it does seem like the typical
       | Rust program with it's massive number of "cargo adds" is an
       | enormous attack surface.
        
         | MattPalmer1086 wrote:
         | It's rare not to use open source libraries no matter the
         | language. Maybe C code tends to use fewer, I don't know.
         | 
         | This doesn't prove anything of course, but the only High
         | severity vulnerability I had in production this year was a C
         | library. And the vulnerability was a buffer overflow caused by
         | lack of memory safety.
         | 
         | So I don't think it's a simple trade off of one sort of vuln
         | for another. Memory safety is extremely important for security.
         | Supply chain attacks also - but using C won't defend you from
         | those necessarily.
        
           | immibis wrote:
           | There's no canonical package manager or packaging convention
           | for C and C++ libraries, since they predate that sort of
           | thing. As a result, there's a lot more friction to using
           | dependencies and people tend to use less of them. Common OS
           | libraries are fair game, and there are some large widely used
           | libraries like boost, but it's extremely unusual for a C or
           | C++ project to pull in 20+ very small libraries. A chunk of
           | functionality has to be quite big and useful before it
           | overcomes the friction of making it a library.
        
           | jacquesm wrote:
           | It is extremely rare for a C build environment to start
           | downloading a massive number of unaudited dependencies from a
           | poorly organized pile of endless layers of repositories. What
           | you might have is a couple of dependencies and then you build
           | the rest yourself. To have 800 unknown co-authors on your
           | 'hello world' app would not happen in C.
           | 
           | There are of course still other vectors for supply chain
           | attacks. The toolchain itself, for instance. But then you
           | fairly quickly get into 'trusting trust' level issues (which
           | are very real!) and you will want an OS that has been built
           | with known clean tools as well.
        
             | acdha wrote:
             | The flip side is that the median C program has more first-
             | party security bugs and likely has third-party bugs
             | included as copies which will be harder to detect and
             | replace. I remember years ago finding that a developer had
             | copied something like a DES implementation but modified it
             | so you had to figure out what they'd customized as part of
             | replacing it.
        
               | jacquesm wrote:
               | So far I have not found this to be the case. Usually
               | stuff is fairly high quality and works for the use cases
               | that I throw at it. Your example sounds like very risky
               | behavior. That stuff is super hard to get exactly right.
        
         | bluGill wrote:
         | The supply chain attack always existed. C because it didn't
         | have a package manager made it slightly harder in that a
         | dependency wouldn't be automatically updated, while Rust can do
         | that. However this is very slight - in linux many people use
         | libraries from a package manager which gets updated when there
         | is a new release - it wouldn't be hard to get a bad update into
         | a package (xz did that).
         | 
         | If you have packages that don't come from a package manager -
         | windows install, phone installs, snap, docker, flatpack, and
         | likely more you have a different risk - a library may not have
         | been updated and so you are vulnerable to a known flaw.
         | 
         | There is no good/easy answer to supply chain risk. It is
         | slightly different on Rust because you can take the latest if
         | you want (but there is plenty of ability to stay with an older
         | release if you want), but this it doesn't move the needle on
         | overall risk.
        
           | semi-extrinsic wrote:
           | Au contraire, the Rust (or other "modern" lang) dependencies
           | come _in addition_ to the OS dependencies. The C (or other
           | "old" lang) programs typically have very few dependencies
           | apart from the OS, with absolutely glacial release cycles.
           | And unless you're on Arch or similar, the OS package manager
           | updates are primarily just minor version bumps.
           | 
           | It seems pretty indisputable that "modern" langs
           | substantially increase your supply chain attack surface. Of
           | course some (like JS) are worse than others.
           | 
           | As a result, whether the net security benefit of using Rust
           | vs C is positive or negative depends heavily on the program
           | in question. There is a huge difference between e.g. Firefox
           | and Wireguard in this respect.
        
             | bluGill wrote:
             | Anyone writing C quickly learns to find third party
             | libraries that do lots of things for them.
        
             | antonvs wrote:
             | > The C (or other "old" lang) programs typically have very
             | few dependencies
             | 
             | Say what now? Have you ever worked on a project that uses
             | C?
             | 
             | We were using 3rd party dependencies in C in the 1980s.
             | 
             | Here's a more current list for C and C++:
             | https://github.com/fffaraz/awesome-cpp
        
           | ploxiln wrote:
           | > it wouldn't be hard to get a bad update into a package (xz
           | did that)
           | 
           | I'd actually call that quite difficult. In the case of xz it
           | was a quite high-effort "long con" the likes of which we've
           | never seen before, and it didn't quite succeed in the end (it
           | was caught before rolling out to stable distros and did not
           | successfully exploit any target). One huge close call, but so
           | far zero successes, over almost 30 years now.
           | 
           | But typo-squatting and hijacked packages in NPM and PyPI,
           | we've seen that 100s of times, many times successfully
           | attacking developers at important software companies or just
           | siphoning cryptocurrency.
        
         | rpcope1 wrote:
         | That same problem bites in other ways too. There was a
         | discussion in I think the Debian mailing lists around Rust
         | applications potentially being slower to patch because
         | everything gets linked in statically (so you can't just patch
         | libssl and pull a new so). I imagine if you have one
         | compromised dependency, it's now going to mean pulling a new
         | version for each and every single package that may have
         | incorporated it, which feels like it's going realistically to
         | mean AAA game assets size updates weekly.
        
       | alganet wrote:
       | "Not made here syndrome" might actually not be a syndrome.
        
         | thewebguyd wrote:
         | Agree. We took NIH too far.
         | 
         | You don't need to pull in a library for every little function,
         | that's how you open yourself up to supply chain risk.
         | 
         | The left-pad fiasco, for example. Left-pad was 11 lines of
         | code. Literally no reason to pull in an external dependency for
         | that.
         | 
         | Rust is doomed to repeat the same mistakes because it also has
         | an incredibly minimal standard library, so now we get micro-
         | crates for simple string utilities, or scopeguard which itself
         | is under ~400 LoC, and a much simpler RAII can be made yourself
         | for your own project if you don't need everything in
         | scopeguard.
         | 
         | The industry needs to stop being terrified of writing
         | functionality that already exists elsewhere.
        
           | jacquesm wrote:
           | > The industry needs to stop being terrified of writing
           | functionality that already exists elsewhere.
           | 
           | I think that like everything else this is about balance.
           | Dependencies appear to be zero cost whereas writing something
           | small (even 400 lines of code) costs time and appears to have
           | a larger cost than pulling in that dependency (and it's
           | dependencies, and so on). That cost is there, it is just much
           | better hidden and so people fall for it. If you knew the real
           | cost you probably would not pull in that dependency.
        
         | teddyh wrote:
         | Relevant, from 2001:
         | <https://www.joelonsoftware.com/2001/10/14/in-defense-of-
         | not-...>
        
       | coolThingsFirst wrote:
       | Not a computer security expert by any stretch of the imagination
       | but why is this difficult to solve, don't do antiviruses check if
       | some program is accessing tokens or something? Maybe even OSes
       | need to have default protection against this, Chrome browser
       | history and tokens.
        
       ___________________________________________________________________
       (page generated 2025-11-06 23:01 UTC)