composer/composer · critical · SecurityException
Invalid package found during dependency resolution, aborting
Error message
Invalid package found during dependency resolution, aborting: {error} What it means
Thrown by ValidatingArrayLoader::validatePackage() (a static, security-sensitive re-check) as a SecurityException when a resolved package's name fails hasPackageNamingError() — i.e. it violates the vendor/name regex, uses reserved names (con/nul/aux/etc.), ends in .json, or contains uppercase. This is a defense-in-depth guard re-applied after dependency resolution, before install/write, to stop malicious names that slipped past earlier validation.
Solutions
- Run 'composer clear-cache' and re-run update to refetch clean metadata from trusted sources.
- Inspect composer.lock for packages with abnormal names; remove offending entries and re-resolve.
- If you control the offending package, rename it to a valid lowercase vendor/name with no reserved words.
- Verify you are resolving against the official packagist.org or a trusted private repository, not a mirrored/poisoned one.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check a resolved package name with the public static guard before install
$err = \Composer\Package\Loader\ValidatingArrayLoader::hasPackageNamingError($package->getName());
if ($err !== null) {
throw new \RuntimeException('Refusing to install: '.$err);
} Type guard
function isSafePackageName(string $name): bool {
return \Composer\Package\Loader\ValidatingArrayLoader::hasPackageNamingError($name) === null;
} Try / catch
try {
\Composer\Package\Loader\ValidatingArrayLoader::validatePackage($package);
} catch (\Composer\Util\SecurityException $e) {
// Do NOT auto-resolve; treat as a security incident and abort the operation.
throw $e;
} Prevention
- Only resolve dependencies from trusted repositories (official packagist.org or vetted private mirrors).
- Commit composer.lock and review diffs in CI so unexpected package additions are caught.
- Keep Composer updated to receive the latest security-validation rules.
When it happens
Trigger: Calling ValidatingArrayLoader::validatePackage($package) where $package is not a RootPackageInterface and getName() returns a value for which hasPackageNamingError() is non-null (structurally invalid name, reserved name, .json suffix, or uppercase letters). Triggered internally during dependency resolution and lock-file writing.
Common situations: A malicious or corrupted provider/lock file injects a package whose name would be interpreted dangerously (e.g. contains shell metacharacters that evade the regex, or a reserved Windows device name). Encountered after a 'composer update' that pulled bad metadata or when a tampered composer.lock is present.
Related errors
- has an invalid , it must not start with a
- has an invalid bin , it must not contain ".." path segments
- 2
- Advisory for could not be loaded as a full advisory from
- Composer rollback failed: an empty signature was downloaded…
AI-assisted analysis of composer/composer@c435d285c9 (2026-08-07).
Data as JSON: /api/errors/8be1b642f78c6b67.
Report an issue: GitHub.
Appendix: source
Thrown at src/Composer/Package/Loader/ValidatingArrayLoader.php:686
* installed from the lock file. This guards against malicious package names and source/dist
* URLs or references that could be interpreted as command-line options (argument injection)
* by the VCS/download tooling.
*
* @throws SecurityException
*/
public static function validatePackage(PackageInterface $package): void
{
// The root package's name/metadata is locally controlled and already validated by
// RootPackageLoader (and its "__root__" placeholder name would be a false positive here).
// RootPackageInterface covers both RootPackage and RootAliasPackage.
if ($package instanceof RootPackageInterface) {
return;
}
// getName() is already lowercased, so the uppercase style branch never fires and only
// structural/security failures throw. Platform packages return null here.
if (null !== ($err = self::hasPackageNamingError($package->getName()))) {
throw new SecurityException('Invalid package found during dependency resolution, aborting: '.$err);
}
// A url or reference starting with a "-" may be misinterpreted as a command-line option
// by the VCS/download tooling, same protection as the source/dist checks done in load().
$sourceDist = [
'source.url' => $package->getSourceUrl(),
'source.reference' => $package->getSourceReference(),
'dist.url' => $package->getDistUrl(),
'dist.reference' => $package->getDistReference(),
];
foreach ($sourceDist as $field => $value) {
if ($value !== null && Preg::isMatch('{^\s*-}', $value)) {
throw new SecurityException($package->getName().' has an invalid '.$field.', it must not start with a "-": '.$value);
}
}
// Bin paths are resolved relative to the package install dir and then chmod'd (and
// proxied) by BinaryInstaller. A ".." segment escapes that directory and lets aView on GitHub (pinned to c435d285c9)