---
# System prepended metadata

title: Notes from "Attacks on Package Managers"

---

# Notes from "Attacks on Package Managers"
https://theupdateframework.io/papers/attacks-on-package-managers-ccs2008.pdf

Packages consist of an archive containing files and additional embedded package metadata. That metadata can contain a signature.

Package metadata is what is downloaded when clients sync a repository. Most repositories have a *root metadata* file as well, that contains the location and hashes of package metadata files. Root metadata, package metadata, and packages can all be signed.

Package manager flow:
- Download root metadata
- Use root metadata to download/verify package metadata
- Use package metadata to download a package and dependencies

# Threats
## Arbitrary Package
A malicious repository can substitute a malicious package for the one the user requests
## Replay attack
A malicious repository can give correctly signed  but outdated packages or metadata, causing clients to install old versions with known vulnerabilities.
## Freeze attack
A variation on the replay attack, a malicious repository can decline to provide updated versions, leaving clients to be stuck on vulnerable versions.
## Extraneous dependencies
A malicious repository can change package metadata to add dependencies to packages
## Endless data
A malicious repository can return an endless stream of data to perform a DOS to the client

# Mitigations
## No signing
If neither the packages, package metadata, or root metadata are not signed, then all attacks above are possible.

## Signed packages
If packages are signed, replay and freeze attacks are still possible by providing forged package or root metadata that list outdated/vulnerable packages.

The package manager must verify that package metadata inside the package matches what is provided by the repository, or else they can forge the outside metadata for an extraneous dependencies attack.

Example:
- Repository lists package metadata `[{"name": "a", deps:["b"], "checksum": "abc123"}, {"name": "b", "checksum": "abc456"}]`
- Client installs `a`, downloads package `a` and `b`, both have valid signatures, match checksums
- Client does not notice that package `a`'s embedded metadata does not contain the `b` dependency

## Signed package metadata
If the package metadata is signed, then this prevents the extraneous dependency attack, since it becomes impossible to forge the metadata that specifies dependencies.

Endless data attacks and freeze attacks are still possible. Depending on how the package metadata is provided, it can also help prevent replay attacks. If it is one signed artifact, then it's impossible to alter individual metadatas, the only viable attack would be to provide an older copy of the entire repository. Additionally the client can verify that when updating the repository the metadata bundle has a newer timestamp than the previous version, to prevent a malicious repository from rewinding to older versions.

Example of freeze attack:
- Repository lists metadata hashes `[{"name": "a", "checksum": "def456"}]`
- Repository lists package metadata `[{"name": "a", "version": "1.0" "checksum": "abc123"}]`
- Client installs `a`, package metadata and package signatures are valid despite it being out of date and containing vulnerabilities

## Signed root metadata
The repository serves a signed root metadata file which contains hashes for each package metadata, which in turn provides hashes for each package. This provides some protection against freeze attacks, since the malicious repository would have to choose a valid root metadata file from some point in history, meaning they can freeze **all** packages to some point in the past, but not individual packages selectively.

To mitigate this, package managers could add an expiration time to root metadata, to allow clients to refuse them if they are too old.

## Standalone packages
Signatures embedded in packages are the most practical option. An alternative considered would be for repositories to host signatures, but this requires the user to have a repository to check against, rather than just the package itself.