Live data from Hacker News

Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

medium.com

401–410 of 412 posts

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#401

Earlier quoted context omitted.

Typically libraries don’t directly load one another. The language runtime does this.

Yes, but authorisation to do so must come from somewhere. In Java it's ambient. In a pure caps system, I'm not sure how it'd work.

The beauty of object-capability security is that it completely aligns with normal object-oriented design. So you can always recast these discussions to not be about security: how would I inject any other new dependency I needed without changing the API of all intermediaries? And there is a whole literature of design patterns for doing this.

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#402
post #392

Earlier quoted context omitted.

In obvious cases like that, I agree with you. In real life however my dependencies are rarely that simple. So let's imagine a REST API library that needs disk and network access to do it's work. How do I know it doesn't abuse my permission? And what about its transient dependencies?

But why would a REST API library need disk access? If it required that, it would raise suspicion for me.

Maybe it support serving files (static content)? Or writing them to disk? Either way can we rather argue the point instead of the example?

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#403

Earlier quoted context omitted.

Yes, but authorisation to do so must come from somewhere. In Java it's ambient. In a pure caps system, I'm not sure how it'd work.

The beauty of object-capability security is that it completely aligns with normal object-oriented design. So you can always recast these discussions to not be about security: how would I inject any other new dependency I needed without changing the API of all intermediaries? And there is a whole literature of design patterns for doing this.

All you'd do there is make the injector a semantic equivalent of the AccessController. The injector must have some sort of security policy after all, to decide whether a component is allowed to request injection of a capability. Whether you structure it as a single subsystem is responsible for intercepting object construction and applying policy based on the home module of what's being constructed, or whether you determine that module via stack walks, the end result is very similar: some central engine decides what components can do and then applies that policy.

The Java approach is nice because it avoids any need for DI. DI is not a widely accepted pattern. There are no DI engines that would have any support for this kind of policy-driven injection. And whilst popular in some areas of software like Java web servers, it hardly features in most other languages and areas, there are no programming languages with built in support for it and that includes modern languages like Kotlin. DI engines meanwhile have changed how they work pretty radically over time - compare something like the original Spring XML DI to Guice to Dagger3. Plus, DI is awkward when the dependency you need isn't a singleton. How would I express for example "I need a capability injected that gives me access to the $HOME/.local/cache/app-name directory"? Annotation based DI struggles with this, but with the AccessController it's natural: the component just requests what it needs, and that's checked against a policy, which can be dynamically loaded from a file, or built by code.

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#404
post #266

Here's the application called deptrust I submitted to the Mozilla Builders program (didn't get in :P) to address this problem space before I had to focus more on my current job. Please let me know if there are any collaborators who would like to work on this together someday! https://docs.google.com/document/d/1EW6uSZB0_D0qZuDSGuxujuVE...

Hey there, any chance you want to turn this doc into a dedicated webpage? Here's a demo: https://demos.writary.app/deptrust

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#405

I see a lot of people saying things like "this is why package signing is important" and "we need to know who the developers are" and "we need to audit everything." Some of that is true to some degree, but let me ask you this: why do we consider it acceptable that code you install through a package manager implicitly gets to do anything to your system that you can do? That seems silly! Surely we can do better than tha…

I'm reading through all these responses and it sounds like nobody read the article. Everybody keeps bringing up JVM SecurityManager, or how granular Deno's permission system is, or a syntax for granting runtime permissions to modules (like your Agoric link). That's not what happened here. The actual attack in the article was a post-install script run by the package manager. That means whatever kind of limits you might place on runtime capabilities of the library wouldn't have mattered. You need a system that lets the package installer request granular permissions from the package manager, where the package manager runs the scripts in a sandbox and only explicitly-provided privileges are granted. I don't know of any package managers that support this feature today.

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#406

Earlier quoted context omitted.

I disagree: the problem is not that package managers make things easy, it's just that several of them are poorly designed. The fact that pip/npm/gem etc. look for packages in a fallback location if not found in the private repository is a terrible design flaw. One which not all package managers have. For example, when you add a cargo dependency from a private registry, you have to specify the registry that the depend…

I haven't used private packages, but it astonishes me you don't just add private packages with some kind of flag so it knows to not try to pull a public package. Anyone who uses this must have already understood and just overlooked this vulnerability when they realize their private package must have a unique name that doesn't match a public package

I was confused by this aspect of the article.

I have scoped, private packages in `@myscope`. I set up my `npmrc` with `@myscope:registry=url/to/my/private/repo`. I just checked, and if I try to install `@myscope/commmon-library`, when it's not found on our repo, it will fail, because `npm` has associated `@myscope` with one and only one (private) registry.

The only hiccup is that if I'm a new developer, and I haven't made this entry in my user-level `npmrc`, and I'm not using an existing project with a `.npmrc` in the project root, then it will try to hit `@myscope` on the public repo. But if I don't have the registry for `@myscope` configured at all, my actual dependencies won't work, so I should notice that right away.

If nothing else, I suppose the takeaway is to grab the group scope for whatever private scope you choose on the public repo before somebody else squats on it. Still, at least for NPM, this seems like a solved problem, you just have to implement the existing solution correctly.

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#407
post #10

I'm flabbergasted by how silly this is. Bump the version and the package manager chooses yours online vs. the private one. Amazing. How silly and how expensive is this going to be as this blatant security issue is going ripple on for the next months to come.

I don't think it actually works this way for NPM specifically, if you're using scoped packages correctly. I believe you can associate a scope with one (private) repo and it will not fall back on the public repo, or choose newer / higher-numbered versions on the public repo over a version from the private one.

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#408

Earlier quoted context omitted.

Migrating from public NPM to a privately-hosted, your own mirror of NPM is not a very complicated process, and if you already have a CI pipeline in place, it can be implemented completely transparently to developers. But as many other things that an organisation has to change as it grows from a single-founder startup to a real company, it's something many people just forget to do until they face the consequences.

Mirrors are great for speed and protecting you from dependencies getting randomly deleted off the public repo, but I don't think they can protect from malicious packages. They'll just get pulled into the mirror. At my last gig (Java), developers reviewed all third-party libraries + dependencies and manually uploaded them to a private Ivy server. I don't think that could work in the Node ecosystem, where every module…

There's even a security-versus-security tradeoff. If you manually review every dependency, are you also going to manually review every update to each of those dependencies? If you add friction to your update process, you're also slowing down your ability to incorporate security fixes. Dependencies find vulnerabilities all the time. If you capture a snapshot of "trusted" dependencies, when are you going to update that snapshot, and how long will your project be vulnerable in the meantime?

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#409

Earlier quoted context omitted.

Scopes were only introduced in NPM 2, and iirc it's still an optional feature. Companies that used NPM early on may have opted to never use those. But that's just NPM, it's an issue in all of the mentioned package managers.

true. simplest solution is just always prioritize internal over external.

Just "prioritizing" doesn't fix it, you have to limit scoped packages to be provided by a single (trusted, internal) repo. Otherwise, what do you do when internal offers v1.2.3 but external says it has v1.99.99?

Re: Dependency Confusion: How I Hacked Into Apple, Microsoft and Other Companies

#410

Earlier quoted context omitted.

The beauty of object-capability security is that it completely aligns with normal object-oriented design. So you can always recast these discussions to not be about security: how would I inject any other new dependency I needed without changing the API of all intermediaries? And there is a whole literature of design patterns for doing this.

All you'd do there is make the injector a semantic equivalent of the AccessController. The injector must have some sort of security policy after all, to decide whether a component is allowed to request injection of a capability. Whether you structure it as a single subsystem is responsible for intercepting object construction and applying policy based on the home module of what's being constructed, or whether you det…

Your argument has gone from “this is impossible with capabilities” to “this doesn’t scale” to “nobody uses design patterns”.

You are confusing DI frameworks (often terrible) with the general concept of dependency injection, which is in fact extremely widely used.

Post reply on HN