{"record":{"id":"8be1b642f78c6b67","repo":"composer/composer","slug":"invalid-package-found-during-dependency-resolution","errorCode":null,"errorMessage":"Invalid package found during dependency resolution, aborting: {error}","messagePattern":"Invalid package found during dependency resolution, aborting: (.+?)","errorType":"exception","errorClass":"SecurityException","httpStatus":null,"severity":"critical","filePath":"src/Composer/Package/Loader/ValidatingArrayLoader.php","lineNumber":686,"sourceCode":"     * installed from the lock file. This guards against malicious package names and source/dist\n     * URLs or references that could be interpreted as command-line options (argument injection)\n     * by the VCS/download tooling.\n     *\n     * @throws SecurityException\n     */\n    public static function validatePackage(PackageInterface $package): void\n    {\n        // The root package's name/metadata is locally controlled and already validated by\n        // RootPackageLoader (and its \"__root__\" placeholder name would be a false positive here).\n        // RootPackageInterface covers both RootPackage and RootAliasPackage.\n        if ($package instanceof RootPackageInterface) {\n            return;\n        }\n\n        // getName() is already lowercased, so the uppercase style branch never fires and only\n        // structural/security failures throw. Platform packages return null here.\n        if (null !== ($err = self::hasPackageNamingError($package->getName()))) {\n            throw new SecurityException('Invalid package found during dependency resolution, aborting: '.$err);\n        }\n\n        // A url or reference starting with a \"-\" may be misinterpreted as a command-line option\n        // by the VCS/download tooling, same protection as the source/dist checks done in load().\n        $sourceDist = [\n            'source.url' => $package->getSourceUrl(),\n            'source.reference' => $package->getSourceReference(),\n            'dist.url' => $package->getDistUrl(),\n            'dist.reference' => $package->getDistReference(),\n        ];\n        foreach ($sourceDist as $field => $value) {\n            if ($value !== null && Preg::isMatch('{^\\s*-}', $value)) {\n                throw new SecurityException($package->getName().' has an invalid '.$field.', it must not start with a \"-\": '.$value);\n            }\n        }\n\n        // Bin paths are resolved relative to the package install dir and then chmod'd (and\n        // proxied) by BinaryInstaller. A \"..\" segment escapes that directory and lets a","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/composer/composer/blob/6ffc1177404d0c50119c22dde6564a380f4a82c9/src/Composer/Package/Loader/ValidatingArrayLoader.php#L668-L704","documentation":"Thrown as SecurityException by ValidatingArrayLoader::validatePackage() during dependency resolution when a resolved package's name fails the naming check (hasPackageNamingError returns non-null). This re-validates packages that may have been loaded through the non-strict ArrayLoader (e.g. from a lock file or a malicious mirror) to block malicious package names, and aborts resolution immediately.","triggerScenarios":"Composer resolves a package whose name is structurally invalid — uppercase characters (names must be lowercase lowercase-with-dashes), or otherwise malformed. Because getName() is already lowercased for normal packages, this typically fires for packages loaded bypassing normal validation: a hand-crafted lock file, a tampered provider, or a non-spec-compliant custom repository.","commonSituations":"A corrupted or tampered composer.lock; a private/custom repository serving non-compliant package metadata; migrating from an old Composer version with looser validation; a package whose name was edited directly in the lock file.","solutions":["Run 'composer validate' and 'composer update --lock' to regenerate lock metadata through the normal loader.","Inspect the offending package name in the error and report/fix the upstream package metadata if it is malformed.","If the source is a custom repository, ensure it emits lowercase, spec-compliant package names.","Clear caches ('composer clearcache') and re-resolve to drop any cached malformed metadata."],"exampleFix":"// before (custom repo packages.json emitting bad name)\n{ \"packages\": { \"MyVendor/MyPkg\": { ... } } }\n// after\n{ \"packages\": { \"myvendor/my-pkg\": { ... } } }","handlingStrategy":"validation","validationCode":null,"typeGuard":"use Composer\\Package\\Loader\\ValidatingArrayLoader;\nuse Composer\\Semver\\VersionParser;\n\nfunction packageNameIsValid(string $name): bool\n{\n    return (bool) preg_match('/^[a-z0-9]([_.-]?[a-z0-9]+)*\\/[a-z0-9](([_.]|-{0,2})?[a-z0-9]+)*$/', $name);\n}","tryCatchPattern":"use Composer\\Package\\Loader\\ValidatingArrayLoader;\nuse Composer\\Package\\Loader\\InvalidPackageException;\ntry {\n    $loader = new ValidatingArrayLoader(new ArrayLoader(null, true), true);\n    $package = $loader->load($pkgData);\n} catch (InvalidPackageException $e) {\n    // report $e->getErrors()\n}","preventionTips":["Always lowercase package names and use the vendor/package format.","Generate lock files with composer update rather than editing them by hand.","Run 'composer validate --strict' on custom repository metadata.","Clear caches when switching mirrors."],"tags":["security","validation","dependency-resolution","package-naming"],"analyzedSha":"6ffc1177404d0c50119c22dde6564a380f4a82c9","analyzedAt":"2026-08-07T00:01:08.491Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}