Composer Says Packages "Were Not Loaded Because They Are Affected by Security Advisories": What to Do
Since Composer 2.9, composer update refuses to install package versions with known security advisories. Here is what the error means, how to fix it properly, and how to ignore a specific advisory with a recorded reason when you genuinely are not affected.
You run composer update and it fails with something like this:
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires acme/pdf-tools ^3.1, found acme/pdf-tools[3.1.0, ..., 3.4.2]
but these were not loaded, because they are affected by security advisories.
Nothing is broken. Composer is refusing to install a package version with a known security vulnerability, and every version your constraints allow is affected. This post covers why it happens, how to fix it properly, and how to ignore one specific advisory safely when you genuinely are not affected.
What changed in Composer
Composer 2.9.0, released in November 2025, added automatic blocking of packages with security advisories. When Composer resolves dependencies, it now skips any version that has a published advisory, using the same advisory data as composer audit.
Composer 2.10.0 (May 2026) moved the settings into a new policy config block. The older audit.* settings still work but are deprecated. Check which version you have before copying config from anywhere, including this post:
composer --version
composer self-update
When blocking applies
Blocking happens during dependency resolution: composer update, composer require and composer remove. Installing from an existing composer.lock with composer install does not block on advisories.
That explains a confusing situation: production deploys keep working, CI installs keep working, and then someone runs composer update locally and it fails. The vulnerable version was already in your lock file. Composer has just stopped letting you choose it again.
To see what in your lock file is affected right now:
composer audit --locked
For a full walkthrough of reading and acting on composer audit output, see Composer Audit: Find Vulnerable PHP Packages.
Fix it properly first
In most cases the advisory has a patched release and your constraint is just too narrow. Work through these in order.
1. Find the advisory and the fixed version.
composer audit --format=plain
Each advisory lists the affected version range and a link (usually a GitHub Security Advisory, GHSA-..., or a CVE). The fixed version is the first one outside the affected range.
2. Widen your constraint to allow the fixed version. If the fix is in 3.5.0 and you require ^3.1 with an upper bound somewhere else, adjust it:
composer require acme/pdf-tools:^3.5 --update-with-dependencies
3. If the package is a transitive dependency, find what is holding it back:
composer why acme/pdf-tools
composer why-not acme/pdf-tools 3.5.0
why-not tells you which of your direct dependencies refuses the fixed version. Updating that dependency usually unblocks it.
4. If there is no fixed release yet, you have a real decision to make: wait, replace the package, or accept the risk for now. Only the last one involves ignoring the advisory.
Ignoring one advisory, with a reason
Sometimes an advisory genuinely does not apply. The vulnerable function is in a code path you never call, or the issue needs a configuration you do not use. In that case, ignore that one advisory ID, and write down why.
Composer 2.10 and later
{
"config": {
"policy": {
"advisories": {
"ignore-id": {
"GHSA-xxxx-xxxx-xxxx": "Only affects the HTML renderer, which we never use. Review 2026-12-01."
}
}
}
}
}
ignore-id also accepts a detailed form if you want the advisory ignored for blocking but still reported by composer audit, which is a sensible default:
"ignore-id": {
"GHSA-xxxx-xxxx-xxxx": {
"on-audit": false,
"reason": "Only affects the HTML renderer, which we never use. Review 2026-12-01."
}
}
Composer 2.9
The equivalent setting is audit.ignore, which takes the same ID-to-reason map:
{
"config": {
"audit": {
"ignore": {
"GHSA-xxxx-xxxx-xxxx": "Only affects the HTML renderer, which we never use. Review 2026-12-01."
}
}
}
}
From 2.9.2, each entry can also take the detailed form {"apply": "block", "reason": "..."} so it is only ignored for blocking.
What not to ignore
Both config styles also let you ignore whole packages or entire severity levels (ignore and ignore-severity under policy.advisories, or audit.ignore-severity on 2.9). Avoid both. Ignoring a package or a severity silences every advisory published against it from now on, including the serious one next month that you would actually care about. An ignore entry should be as narrow as the reason you wrote for it.
Put a review date in the reason, and treat an ignored advisory as a ticket rather than a decision. It is easy to add an ignore during an incident and leave it there for two years.
Bypassing blocking for one command
When you need to get unstuck right now, for example to produce a lock file while you investigate, disable blocking for a single command:
composer update --no-blocking
Or with an environment variable:
COMPOSER_NO_BLOCKING=1 composer update
On Composer 2.9, the flag was --no-security-blocking and the variable COMPOSER_NO_SECURITY_BLOCKING=1. Both still work on 2.10 but are deprecated.
Two things to know:
--no-auditdoes not disable blocking. It only skips the audit summary Composer prints after an install or update.- Do not put
--no-blockingin CI scripts or deploy commands. That turns a one-off workaround into a permanent hole.
Turning it off entirely
You can disable all policy enforcement by setting policy to false (2.10+) or audit.block-insecure to false (2.9). Don't. It removes the protection for every package you will ever add, and the next vulnerable release will install silently.
Keep the check in CI as well
Blocking only protects you when someone runs an update. Your existing lock file can become vulnerable at any time, because advisories are published after you install. Run the audit on every build:
- run: composer install --no-interaction --prefer-dist
- run: composer audit --locked
composer audit exits non-zero when it finds advisories, so the build fails until someone fixes or explicitly ignores them. Since Composer 2.10 the exit code is simply 0 or 1.
roave/security-advisories is an older approach to the same problem: a metapackage that conflicts with every known-vulnerable version. With Composer 2.9's built-in blocking it is largely redundant for resolution, but composer audit in CI is still the piece most teams are missing.
The part Composer cannot see
Composer knows what is in your lock file. It does not know whether the vulnerable code is reachable on your deployed application, whether you deployed the patched lock file to every server, or whether an old release is still running behind a load balancer.
That is the outside view. StackShield checks the deployed Laravel application from the internet, including exposed debug tools and files that dependency audits never look at. Run a free scan to see what your production app exposes, and read about PHP supply chain attacks through Composer for the threats advisory data does not cover.
Is your Laravel app exposed right now?
34% of Laravel apps we scan have at least one critical issue, and most teams do not find out until something breaks. The free scan checks your live app in 60 seconds. Then StackShield re-runs every check after each deploy, so a fix you ship today does not quietly regress next week.
Frequently Asked Questions
Why does Composer say packages were not loaded because they are affected by security advisories?
Since Composer 2.9.0 (November 2025), dependency resolution skips any package version that has a known security advisory. If the only versions matching your constraints are affected, resolution fails with this message. It is a safety feature, not a bug: Composer is refusing to install something known to be vulnerable.
Does Composer block composer install from an existing lock file?
No. Advisory blocking applies when Composer resolves dependencies: composer update, require and remove. Installing from an existing composer.lock does not re-check advisories for blocking, which is why a deploy can keep working while a teammate cannot update. Run composer audit to see the advisories that affect your lock file.
How do I ignore a specific security advisory in Composer?
On Composer 2.10 or later, add the advisory ID to config.policy.advisories.ignore-id in composer.json, ideally as a map of ID to reason. On Composer 2.9, use config.audit.ignore, which accepts the same ID-to-reason map. Ignore single advisory IDs, never whole packages or severities, and record why you are not affected.
How do I temporarily bypass Composer security blocking?
Pass --no-blocking to update, require, remove or install, or set COMPOSER_NO_BLOCKING=1. Older 2.9 releases used --no-security-blocking and COMPOSER_NO_SECURITY_BLOCKING, which still work but are deprecated. Note that --no-audit does not disable blocking; it only skips the audit report after install.
Should I turn advisory blocking off entirely?
No. Setting policy (or audit.block-insecure on 2.9) to false removes the protection for every package, including advisories published next month. Fix the dependency, or ignore one specific advisory with a reason and a review date. That keeps the safety net in place for everything else.
Related Articles
StackShield Now Has an MCP Server: Run Scans and Triage Issues From ChatGPT, Claude and Cursor
Connect StackShield to any MCP-compatible assistant and ask it to scan a domain, explain a failed test, resolve the issues you have fixed, or write a security report. Included on every plan.
SecurityLaravel 12 vs 13: What Actually Changed, and When You Need to Upgrade
Laravel 13 is a small upgrade with a few changes that matter: PHP 8.3, origin-aware CSRF protection, hardened cache unserialization and JSON session serialization. Here is the side-by-side, the support dates, and the upgrade items that can log your users out.
SecurityYour Laravel APP_KEY Leaked: What an Attacker Can Do, and How to Rotate It Safely
Researchers found more than 260,000 Laravel APP_KEYs in public GitHub repositories, and hundreds of live applications still using them. What a leaked key actually exposes, why APP_PREVIOUS_KEYS can keep a leaked key working, and the rotation steps in the right order.
Compare StackShield
Security Checklists
Laravel Production Deployment Security Checklist
A comprehensive security checklist for deploying Laravel applications to production. Covers environment config, server hardening, access control, and monitoring.
20 itemsLaravel API Security Checklist
Secure your Laravel API endpoints against common vulnerabilities. Covers authentication, input validation, rate limiting, and response security.
Stay Updated on Laravel Security
Get actionable security tips, vulnerability alerts, and best practices for Laravel apps.