Safeguard
Software Supply Chain•

How do you manage PHP dependencies securely with Composer?

Commit composer.lock, deploy with install not update, run composer audit in CI, and skip dev packages in production. A short checklist for PHP teams.

Safeguard Security Team
4 min read

Manage PHP dependencies securely by committing composer.lock, deploying with composer install so exact versions are used, running composer audit in CI against the lock file, and installing without dev packages in production. Composer gives you each of these controls; the work is making them routine.

Why does the lock file matter for security?

The Composer docs explain the split. update resolves what composer.json allows, picks the latest matching versions, and writes them to composer.lock. install then uses the exact versions in that file when it exists. The docs say this is by design, so your project does not break from unexpected dependency changes.

That is a security property as much as a stability one. If a package maintainer account is hijacked and a bad release appears, a deploy that runs update pulls it in on the spot. A deploy that runs install keeps the version you reviewed.

For applications, the docs say to commit the lock file so everyone is locked to the same versions. For libraries, committing it is not necessary.

Should the vendor directory be committed?

The docs generally recommend against it. Add it to your ignore file and let Composer install during bootstrapping, on developer machines, build servers and deploy tools. Committing vendor increases repository size, creates large diffs and duplicates dependency history.

One side effect for review: with the lock file as the source of truth, a pull request that changes it shows a precise list of what moved.

What does composer audit check?

The audit command checks installed packages against dependency policies. According to the CLI reference, that covers security advisories (from Packagist.org by default, or other repositories you configure), abandoned packages, malware and other configured policies.

Useful options from the page:

  • --locked audits what is in the lock file, regardless of what is in vendor.
  • --no-dev skips require-dev packages.
  • --abandoned takes ignore, report or fail.
  • --format can be table, plain, json or summary.
  • --ignore-severity can be passed several times.

Exit code 0 means no issues, and 1 means packages matched a policy or the command could not run because packages were missing. That makes it simple to fail a CI job.

What is a safe CI sequence?

A constructed example for a web application:

composer validate --strict
composer install --no-dev --no-interaction
composer audit --locked --abandoned=fail

The validate command checks composer.json and, if a lock file exists, that it is up to date, and --strict turns warnings into failures. The page suggests running it before committing and before tagging a release. In practice you may want to run audit against the full lock file, including dev packages, in a separate job, since build tooling is also part of your supply chain.

What about environment settings?

The CLI page lists a few worth knowing. COMPOSER_NO_DEV=1 has the same effect as --no-dev on install. COMPOSER_AUDIT_ABANDONED sets the abandoned-package behavior. COMPOSER_NO_AUDIT disables the audit step on require, update, remove and create-project, so check nobody sets it in CI by accident. The --no-secure-http option on create-project is described by the docs as a bad idea.

Also, COMPOSER_ALLOW_SUPERUSER is meant only for containers where Composer always runs as root.

What to do

  1. Commit composer.lock for every application and review changes to it in pull requests.
  2. Deploy with composer install, never composer update.
  3. Run composer audit --locked in CI and decide whether abandoned packages should fail the build.
  4. Install with --no-dev for production images.
  5. Run composer validate --strict before release tags.
  6. Update one package at a time with composer update vendor/package when you need a fix, so the diff stays small.
  7. Keep vendor out of version control.
  8. Check CI for COMPOSER_NO_AUDIT and other overrides.

Safeguard can generate an SBOM and scan your PHP dependencies for known vulnerabilities, and its policies and gates can block a merge on rules you set. That adds a second opinion beside Composer's own advisory data.

Quick check

Is composer install or composer update safer for deployment?

Install. It uses the exact versions in composer.lock, so a new upstream release does not enter production unreviewed.

Does a clean composer audit mean no vulnerable code?

No. It checks against advisory and policy data. Unreported flaws and malicious releases not yet flagged will not appear.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.