// back_to_blog Laravel

Composer Lockfiles and MFA: Small Habits That Cut Supply-Chain Risk

Jul 16, 2026 · 2 min read · 3 tags
Composer Lockfiles and MFA: Small Habits That Cut Supply-Chain Risk

Lockfiles are not optional

I commit composer.lock for applications. Production deploys should run composer install, not a casual composer update, unless I am deliberately reviewing upgrades. The lockfile is how I know which versions actually shipped.

# CI / production
composer install --no-dev --optimize-autoloader

# Local intentional upgrades (review the diff)
composer update vendor/package
git diff composer.lock

install vs update (say it out loud)

  • composer install — installs from the lockfile (reproducible)
  • composer update — resolves anew and rewrites the lockfile

Mixing them up in deploy scripts is how “works in staging, different in prod” happens.

MFA everywhere publishers live

GitHub, Packagist, and npm publisher accounts need MFA. Account takeover is one of the most common ways malicious package versions ship—see recent npm phishing campaigns and PHP ecosystem incidents alike.

Prefer known maintainers for critical paths

Auth, payments, and encryption should not come from a random one-person package with no release discipline if a first-party or well-known alternative exists. That is a big reason I like Laravel’s official packages for common web needs.

Post-incident checklist

When something like the laravel-lang tag-rewrite incident happens:

  1. Identify whether you depend on the package (directly or transitively).
  2. Compare composer.lock hashes / package refs to known-good releases.
  3. Rebuild from a clean environment; avoid composer update blind.
  4. Rotate CI secrets / deploy tokens if the pipeline could have been poisoned.
  5. Watch Packagist/GitHub advisories for the recovery path.

npm side note

This site still uses npm for Vite. Same rules: commit package-lock.json, prefer npm ci in CI, MFA on the npm account. The Laravel essay covers why I still default to Composer for backend critical path.

Troubleshooting and common mistakes

Most failures I see are configuration and process issues, not “the framework is broken.” Slow down: reproduce on a clean environment, read the exact error, and change one variable at a time.

  • Confirm you are on the documented major version of the tool you are following.
  • Prefer official docs over random outdated blog snippets when commands disagree.
  • Keep lockfiles committed so teammates and CI install the same dependency graph.
  • Separate “works on my machine” fixes (PATH, SDK licenses, local services) from application bugs.

What to do next

Implement the smallest vertical slice from this article on a throwaway branch, then promote the patterns into your real app. Guides that stay theoretical never catch the auth, env, and deploy footguns that actually burn time.

CI pattern I recommend

# GitHub Actions-style sketch
- uses: php-actions/composer@v6
  with:
    command: install
    args: --no-dev --optimize-autoloader --prefer-dist

Cache Composer’s cache directory, but never skip the lockfile. Fail the build if composer.lock is missing on an application repo.

Private packages

For proprietary code, use private Satis/Packagist or VCS repositories with deploy tokens scoped as tightly as possible. Treat those tokens like production secrets.

Enjoyed this article?

Explore more posts or get in touch about a project.