Setup Debian Proxy with DevGuard Dependency Proxy

System packages are part of your supply chain too. In 2024, the backdoored xz-utils releases 5.6.0 and 5.6.1 (CVE-2024-3094) reached Debian testing and unstable before the backdoor was discovered, and every container image or server that ran apt-get upgrade against those suites pulled them in. Because base images and CI runners install system packages on every build, a single compromised .deb reaches a large part of your infrastructure within hours.

The DevGuard dependency proxy sits between apt and the Debian archive. Every package download is checked against the OSV dataset before it reaches your system, blocking known malicious packages automatically.

  • Registry URL: <your-devguard-url>/api/v1/dependency-proxy/<secret>/deb/debian
  • Security updates: <your-devguard-url>/api/v1/dependency-proxy/<secret>/deb/debian-security

Replace <secret> with the dependency proxy secret of your organization, project or repository. The complete proxy URLs are shown in its Dependency Proxy Settings in DevGuard.

Configuration

Since Debian 12, apt reads its package sources from /etc/apt/sources.list.d/debian.sources. Point both the main archive and the security archive at DevGuard by replacing the default mirror:

Afterwards, the file looks like this:

Types: deb
URIs: https://<your-devguard-url>/api/v1/dependency-proxy/<secret>/deb/debian
Suites: trixie trixie-updates
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.pgp

Types: deb
URIs: https://<your-devguard-url>/api/v1/dependency-proxy/<secret>/deb/debian-security
Suites: trixie-security
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.pgp

Once set, all apt-get update, apt-get install and apt-get upgrade invocations go through DevGuard transparently. In a Dockerfile, run the sed command before the first apt-get update.

Blocked packages and signed package lists

For npm, Go and PyPI, the proxy removes blocked versions from the version list, so the client resolves to the next allowed version. This is not possible for Debian: the package lists are signed through InRelease, and any change would break the signature check of apt.

apt therefore always sees the newest version, tries to download it, receives 403 Forbidden and aborts. This applies to malicious packages and to the minimum package age alike. To install an older version, pin it explicitly, for example with apt-get install <package>=<version>, as long as that version is still available in the archive.

Testing

DevGuard ships a test package, fake-malicious-package, that is permanently flagged as malicious for all versions. The script below runs apt in a throwaway debian:trixie-slim container whose only package source is the DevGuard proxy, so your own system stays untouched:

fake-malicious-package does not exist in the Debian archive, so apt cannot request it. The proxy checks a download against the malicious package database before fetching it from upstream, so the curl request above proves the check without a real package.

Testing the minimum package age

The minimum package age is configured per repository and only applies to requests using the repository's proxy URL, which contains a secret. The proxy uses the upload time the Debian archive reports for each .deb file.

To verify it, temporarily set the minimum age to 87600 hours (10 years). hello 2.10-5 was uploaded to trixie in April 2025, so the proxy must reject it. As described above, apt does not fall back to an older version but aborts:

Further Reading

Have feedback? We want to hear from you!

Fields marked with * are required