Setup Composer Proxy with DevGuard Dependency Proxy

PHP projects are just as exposed to supply chain attacks as any other ecosystem. In 2022, attackers took over the abandoned hautelook/phpass package on Packagist and published new releases that stole AWS credentials from every environment that installed them. In 2026, attackers used compromised GitHub accounts to publish malicious tags of intercom/intercom-php and the laravel-lang packages. Because Composer resolves the whole dependency tree automatically, a single compromised package is enough to reach every developer machine and CI runner of a project.

Composer and Packagist have responded with several hardening measures: Packagist flags malware versions and makes stable versions immutable, and Composer 2.10 introduced the policy config, which blocks flagged malware versions, security advisories and abandoned packages by default. These measures only apply to clients running a recent Composer version, and each project can relax or disable them in its own composer.json.

The DevGuard dependency proxy sits between Composer and Packagist and enforces protection centrally, for every Composer version and without any client configuration. Every package request is checked against the OSV dataset before it reaches your vendor directory, blocking known malicious packages automatically. Combined with the minimum package age, the proxy complements Composer's own policies rather than replacing them.

  • Registry URL: <your-devguard-url>/api/v1/dependency-proxy/<secret>/composer

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

Disable the default Packagist repository and add the DevGuard proxy instead. Disabling packagist.org is required: otherwise Composer keeps it as a fallback and downloads packages directly from Packagist whenever the proxy does not serve them. To apply it to every project on your machine, set it in your global Composer configuration:

To scope it to a single project, run the same commands without --global in the project directory. Composer then adds the repositories to your composer.json:

Run composer config repositories to verify that the DevGuard proxy is the only repository left.

Once set, all composer install, composer update and composer require invocations resolve packages through DevGuard transparently.

Testing

DevGuard ships a test package, fake-org/malicious-package, that is permanently flagged as malicious for all versions. The script below uses a project-local Composer home and cache, so every download goes through the proxy and your global configuration stays untouched:

If the install is blocked, the proxy is working correctly. Composer reports the 403 Forbidden for the package's metadata file. All other packages resolve normally from Packagist.

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 release time Packagist reports for each version: versions that are too new are removed from the package metadata, so Composer resolves to the newest version that is old enough, and downloads of a too new version are rejected.

To verify it, temporarily set the minimum age to 87600 hours (10 years). monolog/monolog 3.7.0 was published in June 2024, so the proxy must reject it, while composer require without a version still resolves to an older version:

Further Reading

Have feedback? We want to hear from you!

Fields marked with * are required