Join our Newsletter — 33% off our NHI Course
Home› Guides› Composer and Packagist Supply Chain Security Guide: Lock…
Guide Software & AI Supply Chain

Composer and Packagist Supply Chain Security Guide: Lock Files, Plugins, Audit and Private Repositories

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 11 November 2026 14 min read
On this page

Every PHP application built with Composer runs code from hundreds of maintainers it has never met, and in 2026 attackers showed they can change what an existing, trusted version installs by rewriting Git tags. Composer and Packagist.org have added strong controls in response: plugin allowlisting, a unified dependency policy that blocks malware and vulnerable versions, a cooldown period for new releases, and repository priorities that defeat dependency confusion. Most of them only help if you configure them deliberately. This guide covers how Composer resolves and installs code, where the trust boundaries are, the exact configuration that hardens a project, how to run private repositories and credentials safely, and how to detect and respond to a compromised package. It is written for PHP developers, platform engineers and application security teams, and reflects Composer 2.11 (current at 11 November 2026).

Key takeaways

  • The lock file is your security boundary. Commit composer.lock, install from it in CI and production, and review every change to it like code.
  • Plugins run code; dependency scripts do not. Composer only executes scripts defined by the root package, but plugins execute during every run, so keep allow-plugins explicit and short.
  • Composer 2.10 and later can block bad versions. The config.policy block covers security advisories, malware and abandoned packages, and Composer 2.11 adds a cooldown period for new releases.
  • Repository order matters. All repositories are canonical by default in Composer 2, which stops a public package from overriding your private one; do not turn that off.
  • Tokens are the real target. GitHub tokens, Packagist credentials and auth.json files are what attackers use to publish malicious versions and what stealers harvest from developer machines.

How Composer installs code and where trust is placed

Composer reads composer.json, resolves version constraints against the configured repositories (Packagist.org is added implicitly as the last one unless disabled), writes the exact resolved versions to composer.lock, and downloads each package as a dist archive or a source checkout. By default since Composer 2.1 it installs from dist. Packagist.org itself mostly stores metadata: package versions map to tags and commits in the maintainer's VCS repository, so whoever controls the repository and its tags controls what users receive.

StageTrust assumptionHow it is attackedMain control
Maintainer account (Packagist, GitHub)Only the maintainer can publish or repoint a packageCredential stuffing, stolen tokensMFA, short-lived and narrowly scoped tokens
VCS tagsA released version does not changeTags rewritten to point at malicious commitsLock file with commit references and hashes; Packagist version immutability; cooldown
Package resolutionThe name resolves to the intended sourceDependency confusion, typosquattingCanonical repositories, only filters, intake review
Install timeInstalling does not execute untrusted codeMalicious pluginsallow-plugins, --no-plugins where possible
RuntimeVendor code is what was reviewedAutoloaded files executing on every requestLock review, malware policy, runtime monitoring

The Packagist.org team's May 2026 security update describes two such incidents that year, intercom/intercom-php (30 April 2026) and laravel-lang (22 May 2026), and notes that attackers often modified existing Git tags after the fact. In the Laravel-Lang Composer compromise, a stolen GitHub token with organisation-wide push access was used to repoint release tags to commits in a fork; a new file ran whenever Composer's autoloader loaded and fetched a credential stealer. An earlier incident in May 2023 showed the account layer: Packagist reported that an attacker used passwords leaked from other services to access four inactive maintainer accounts with access to 14 packages and pointed them at forks (no malicious code was distributed in that case).

Lock files and reproducible installs

  • Commit the lock file for applications: composer install installs exactly what is locked; composer update re-resolves. CI and production should only ever run install.
  • Review lock diffs: Packagist's advice after the 2023 takeover was to review lock file changes for untrusted dependencies or external URLs. Look for new packages, changed source or dist URLs, unexpected references, and versions published in the last few days.
  • Use Composer's integrity checks: composer validate confirms the lock file matches composer.json, and Composer 2.11 makes install fail when the lock file has a content-hash merge conflict.
  • Treat the lock as input, not just output: Composer 2.11.2 (released 11 November 2026) fixed several issues that a crafted composer.lock or vendor/composer/installed.json could trigger, including arbitrary command execution and credentials being sent to other hosts. Upgrade Composer itself, and do not accept lock file changes from untrusted pull requests without review.
  • Keep production lean: install with --no-dev and an optimised or authoritative classmap (--classmap-authoritative), and never place vendor/ under the web root. CISA's KEV catalogue includes CVE-2017-9841, a PHPUnit command injection that is exploitable when development dependencies are reachable over HTTP.

Plugins and scripts

Composer's documentation states that only scripts defined in the root package's composer.json are executed; scripts declared by dependencies are ignored. That is a meaningful difference from ecosystems where every dependency can run install hooks. Plugins are the exception: a package of type composer-plugin runs code inside Composer during install and update.

  • allow-plugins: since Composer 2.2.0 this setting controls which plugins may execute. It defaults to {}, which allows none; entries are package name patterns set to true (allow) or false (disallow and stop prompting). Avoid wildcards such as "*": true, and prefer exact names over vendor patterns for third parties.
  • Non-interactive runs: in CI Composer fails rather than prompting when an unlisted plugin appears, which surfaces a new plugin as a build failure instead of silently running it.
  • Disable when not needed: --no-plugins and --no-scripts are available for jobs that only need files on disk, such as dependency analysis or SBOM generation.
  • Autoload files: packages can declare autoload.files entries that are included whenever the autoloader loads. This is how the Laravel-Lang payload ran, and it is why a reviewed lock file matters more than install-time controls alone.

Dependency policy: advisories, malware, abandoned packages and cooldown

Composer 2.10.0 (28 May 2026) introduced the config.policy block, replacing most of the older config.audit settings, which still work as a fallback. Composer 2.11.0 (29 October 2026) added cooldown. The defaults below are from Composer's configuration documentation.

PolicyDefault behaviourKey optionsRecommended setting
advisoriesblock: true (versions with active advisories cannot be installed during update, require or remove); audit: failignore-id with reasons and on-block/on-audit scoping; ignore-severityKeep defaults; record every ignore with a reason and review date
malwareblock: true; block-scope: all (update and install); audit: failignore, ignore-sourceKeep defaults so a version flagged after locking fails the next install
abandonedblock: false; audit: failignore with reasonsReport in CI; set block to true for new projects
cooldown (2.11+)period: null (off)period such as "7 days"; ignore for your own vendor namespaceSet a period (NHI Mgmt Group suggests 3 to 7 days) and exempt internal packages

The cooldown is measured from the publication time reported by the repository (published-time, which Packagist.org provides), which package authors cannot influence. It never withholds dev versions, locked packages that are not being updated, or platform packages. Packagist.org imports malware detection results from Aikido (since March 2026), published as a filter list under CC-BY 4.0 and enabled in Composer without configuration.

Bypass switches: --no-blocking (or COMPOSER_NO_BLOCKING) disables all policy blocking for a command, and "policy": false disables it entirely. Search pipelines and Dockerfiles for both; they should only appear in a documented emergency.

composer audit: reports advisories, malware, abandoned packages and custom policy matches, returning exit code 0 for no issues and 1 for findings. Run composer audit --locked in CI so the check covers what will be deployed, and use --format=json to feed findings into your vulnerability tooling. See the Software Composition Analysis (SCA) Guide.

Private repositories, priorities and dependency confusion

Composer's repository priorities article explains the risk directly: if a private repository were not canonical and someone published foo/bar 2.999 to Packagist.org, Composer would pick the higher public version. In Composer 2 all repositories are canonical by default, so a package found in a higher-priority repository is never loaded from a lower one.

  • Never set "canonical": false on a private repository unless you understand the override risk.
  • Filter repositories: use only or exclude so each repository serves only the vendor namespaces you expect.
  • Register your vendor prefix publicly: claiming your vendor name on Packagist.org prevents others publishing under it.
  • Mirror and proxy: a private repository (Satis, a hosted private Packagist service or an artefact manager) gives you a cached copy of every version you depend on, an approval point, and protection when an upstream tag is rewritten. Disable Packagist.org entirely in projects that should only resolve through the proxy. See the Private Package Repository and Proxy Guide and the Malicious Package and Dependency Confusion Guide.
  • Transport: secure-http defaults to true and restricts downloads to HTTPS; disable-tls is documented by Composer as a security risk. Neither should be changed.

Where identity fits: tokens and auth.json

Composer credentials are non-human identities with direct supply chain impact. Composer can read them from a project auth.json, a global auth.json, composer.json itself, or the COMPOSER_AUTH environment variable.

  • Project auth.json: Composer's documentation says to make sure it is in .gitignore. Add it to secret scanning rules as well.
  • COMPOSER_AUTH: preferred in CI from a secrets manager, but Composer warns that values set on the command line may persist in shell history files.
  • Read-only, scoped tokens: tokens used to install private packages need read access to specific repositories only. GitHub tokens with organisation-wide write access are what made the Laravel-Lang attack possible. See the GitHub Personal Access Tokens Security Guide.
  • Maintainer accounts: enable MFA on Packagist.org and on the VCS host. Packagist's May 2026 update states MFA is available but not yet mandatory, with mandatory MFA planned.
  • Developer machines: stealers delivered through packages harvest auth.json, Git credentials and cloud keys. After any malicious package install, rotate every credential reachable from that machine or runner.

Implementation roadmap

  1. Upgrade Composer: standardise on the current 2.11.x release in developer images and CI, so policy blocking, cooldown and the latest lock file fixes apply.
  2. Baseline: run composer audit --locked --format=json across all repositories; record findings, abandoned packages and the plugins each project allows.
  3. Tighten configuration: commit explicit allow-plugins, keep policy defaults, set a cooldown with internal namespaces exempted, and add only filters to private repositories.
  4. Enforce in CI: fail builds on composer audit findings and on lock file drift; flag new plugins and new direct dependencies for review. Start in report mode ("audit": "report") for one sprint if the backlog is large, then switch to fail.
  5. Introduce a proxy: route installs through a private repository, then disable Packagist.org in production builds.
  6. Fix credentials: move tokens into a secrets manager, scope them read-only, set expiry, and enable MFA for all maintainers of your published packages.
  7. Rehearse response: run a tabletop where a direct dependency's tags are rewritten. Rollback is reinstalling from a known-good lock file and cached dist archives.

Decision guidance

  • Cooldown length: longer periods catch more malicious releases before you install them but delay security fixes. Use ignore or a targeted update for urgent patches rather than shortening the period for everything.
  • Proxy or direct: a small team with few dependencies can rely on lock review, policy defaults and cooldown. Larger organisations, and anyone publishing packages others depend on, benefit from a proxy that caches versions and centralises policy.
  • Libraries versus applications: libraries usually do not ship their lock file to consumers; their security depends on maintainer account protection, signed tags and narrow tokens. Applications should always commit and enforce the lock.
  • Automated updates: dependency bots are valuable, but auto-merging lock changes removes the review step attackers rely on you skipping. See the Dependency Update Automation Guide.

Detection and measurement

  • Lock file changes: alert on new packages, changed source URLs or references for an unchanged version number, and versions younger than your cooldown.
  • Policy bypasses: any use of --no-blocking, COMPOSER_NO_BLOCKING or "policy": false in pipelines.
  • Runtime behaviour: PHP processes making outbound connections to unknown hosts or reading credential files after a deployment.
  • Packagist transparency log: watch ownership, maintainer and version reference changes for your critical dependencies.

Metrics: percentage of repositories with an explicit allow-plugins list and no wildcards; percentage running composer audit --locked as a blocking CI step; mean time to remediate high and critical advisories; number of active advisory ignores past their review date; percentage of Composer tokens that are read-only and expiring; percentage of builds resolving only through the internal proxy.

Common failure patterns

  • Running composer update in CI or production: silently pulls whatever is newest, including a version published minutes ago.
  • Wildcard plugin approval: "allow-plugins": true or broad vendor patterns approve any future plugin.
  • Exposed vendor directory: development tools such as PHPUnit reachable over HTTP, as in CVE-2017-9841.
  • Committed auth.json or tokens in Dockerfiles: private repository tokens end up in Git history and image layers. See the PHP and WordPress Security Guide for the wider PHP hardening picture.
  • Permanent ignores: advisories ignored to unblock a release and never revisited.
  • Over-scoped maintainer tokens: one token with write access to every repository in an organisation, as in the Laravel-Lang case.

Framework mapping

FrameworkReferenceHow it applies
NIST SP 800-53 Rev. 5SR-3 Supply Chain Controls and Processes; SR-4 Provenance; SR-11 Component Authenticity; SI-7 Software, Firmware, and Information Integrity; RA-5 Vulnerability Monitoring and Scanning; IA-5 Authenticator Management; CM-7 Least FunctionalityRepository and intake controls; lock file references; malware blocking; audit; token management; plugin restriction
NIST CSF 2.0GV.SC-05; GV.SC-07; ID.AM-02; ID.RA-01; PR.PS-02Supply chain requirements and monitoring; dependency inventory; advisories; keeping packages maintained
CIS Controls v8.1Control 2 (Software Assets), 7 (Continuous Vulnerability Management), 16 (Application Software Security)Dependency inventory, audit and remediation, secure build practice
ISO/IEC 27001:2022 Annex AA.5.21 Managing information security in the ICT supply chain; A.8.8 Management of technical vulnerabilities; A.8.28 Secure codingThird-party code governance, advisory handling, dependency practice
MITRE ATT&CKT1195.001 Compromise Software Dependencies and Development Tools; T1552.001 Credentials In FilesMalicious package versions; theft of auth.json and other credential files
MITRE CAPECCAPEC-538 Open-Source Library ManipulationTag rewriting and malicious releases

Practitioner checklist

NHI Mgmt Group recommends the following checks.

  • Run Composer 2.11.x everywhere, including CI images and developer containers.
  • Commit composer.lock, run only composer install in CI and production, and review lock diffs.
  • Keep an explicit, minimal allow-plugins list with no wildcards.
  • Keep advisory and malware blocking on, set a cooldown period, and document every ignore with a reason.
  • Run composer audit --locked as a blocking CI step and send JSON output to your vulnerability tracker.
  • Keep private repositories canonical, filter them with only, and route installs through a proxy.
  • Store Composer credentials in a secrets manager, scope them read-only, and keep auth.json out of Git and images.
  • Deploy with --no-dev and keep vendor/ outside the web root.
  • Enable MFA for every maintainer of packages you publish.

Standards and references

Related NHI Mgmt Group resources: Malicious Package and Dependency Confusion Guide · Package Registry Security Comparison Guide · Private Package Repository and Proxy Guide · Open source package compromise

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 11 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.