Most code in a modern application was written by people the developers have never interacted with. Securing that arrangement is difficult because the trust is transitive and largely invisible.
Dependencies are trust decisions made in bulk
Adding one package can pull in dozens more, each maintained separately. The developer evaluated one project and implicitly accepted the rest.
Those transitive dependencies update on their own schedules, so the code being built today may include components that changed since the last review.
Nobody reads it all, and no realistic process could. The scale of the tree makes manual inspection impossible rather than merely inconvenient.
Build systems execute untrusted code
Installing a package often runs scripts on the build machine with the permissions that machine holds. Compromise at that point precedes any security scanning of the artefact.
Build environments typically hold signing keys, deployment credentials and access to internal networks, which makes them a higher-value target than the application itself.
This is why isolating builds, restricting network access during them and separating signing from building have become standard recommendations.
Account takeover is the common route
Publishing a malicious version rarely requires breaking cryptography. It requires access to a maintainer account, which is protected like any other account.
Ownership transfers create another path, since a maintainer stepping back may hand a widely used package to someone whose intentions are unverified.
Registries have responded with stronger authentication requirements and provenance records, though coverage across the enormous number of existing packages remains uneven.
Version pinning trades one risk for another
Fixing exact versions prevents an unexpected update from entering a build, which limits exposure to a compromised release published after the pin was set. Builds also become reproducible, which matters when investigating what shipped.
It also means security fixes are not received automatically, so a pinned project accumulates known vulnerabilities until someone updates deliberately. The risk moves from surprise changes to stale ones.
Lock files attempt to hold both properties by recording exact resolved versions while allowing deliberate updates, though they only help if the file is committed and the build actually honours it.
Inventory is the prerequisite for everything else
Responding to a disclosed vulnerability requires knowing which systems contain the affected component, which is surprisingly difficult once builds are numerous and long-lived.
Machine-readable inventories generated at build time address this by recording exactly what went into each artefact, so the question becomes a lookup rather than an investigation.
The value shows up under time pressure: organisations that can answer the question in hours contain an incident, and those that cannot spend the first days working out what they run.