Stable Dependencies Analyzer
| Analyzer ID | Category | Severity | Time To Fix |
|---|---|---|---|
stable-dependencies | 🛡️ Security | Medium | 30 minutes |
What This Checks
Configuration checks (always performed):
- Flags dangerous
minimum-stabilityvalues (dev,alpha,beta,RC) - Warns when
prefer-stableis not enabled - Optionally flags missing
minimum-stability(see Configuration below)
- Flags dangerous
Version constraint checks (in
requireandrequire-dev):- Detects
dev-*,*-dev,@alpha,@beta, or@RCconstraints - Severity is risk-based: Medium for
require, Low forrequire-devwhenminimum-stability: stable
- Detects
Installed package verification:
- Parses
composer.lock(bothpackagesandpackages-dev) for installed unstable versions - Executes
composer update --dry-run --prefer-stableto detect if updates would change packages - Uses locale-independent pattern matching (works with non-English Composer output)
- Parses
Why It Matters
- Supply chain risk: dev branches and pre-release tags often get force-pushed or deleted, making builds non-repeatable and hiding malicious commits.
- Missing security patches: unstable channels frequently skip CVE backports or break BC, leading to silent regressions in production.
- CI/CD drift: when minimum stability isn't "stable",
composer installin CI can pull new dev snapshots that were never tested locally. - Audit requirements: many compliance frameworks (SOC2, ISO 27001) require documenting that only stable vendor releases reach production.
How to Fix
Quick Fix (5 minutes)
- Force stable defaults and prefer-stable resolution:
composer config minimum-stability stable
composer config prefer-stable true- Update any unstable constraints to tagged releases.
The analyzer detects all Composer-valid unstable version formats:
**Before (❌ All detected as unstable)**
{
"require": {
"vendor/package": "dev-master", // dev branch
"vendor/another": "2.0.x-dev", // dev version suffix
"vendor/tool": "1.0.0-alpha", // alpha with dash
"vendor/lib": "1.0.0alpha", // alpha without dash
"vendor/beta": "v1.0.0-beta", // beta with v prefix
"vendor/rc": "1.0.0RC1", // RC without dash
"vendor/flag": "^2.0@dev" // stability flag
}
}
**After (✅ All stable)**
{
"require": {
"vendor/package": "^2.3",
"vendor/another": "^2.0",
"vendor/tool": "^1.0",
"vendor/lib": "^1.0",
"vendor/beta": "^1.0",
"vendor/rc": "^1.0",
"vendor/flag": "^2.0"
}Supported Unstable Formats
The analyzer correctly identifies all these as unstable:
- Dev:
dev-master,dev-main,2.0.x-dev - Alpha:
1.0.0-alpha,1.0.0alpha,v1.0.0-alpha,1.0.0-alpha.1 - Beta:
1.0.0-beta,1.0.0beta2,v1.0.0-beta,1.0.0-beta.2 - RC:
1.0.0-RC,1.0.0RC1,v1.0.0-RC,1.0.0-RC.1 - Flags:
^2.0@dev,^1.0@alpha,^1.0@beta,^1.0@RC
- Regenerate the lock file with stable versions only:
composer update --prefer-stableProper Fix (30 minutes)
Audit constraints: list every package that uses
@alpha,@beta,dev-*, or*-devand verify why it was pinned that way.Coordinate releases: work with vendors (or tag your own release) instead of depending on mutable branches.
Prioritize by risk:
- High priority: Fix unstable packages in
require(Medium severity, affects production) - Medium priority: Fix unstable packages in
require-devwhenminimum-stabilityis notstable(can leak dependencies) - Low priority: Consider fixing unstable packages in
require-devwhenminimum-stability: stable(Low severity, isolated to dev)
- High priority: Fix unstable packages in
Set minimum-stability to stable (if not already):
bashcomposer config minimum-stability stableThis prevents unstable
require-devdependencies from leaking into production.Regenerate and verify:
bashcomposer update --prefer-stable git diff composer.lockEnsure Composer reports
Nothing to install or updateafterwards.Lock it down in CI: add
composer update --dry-run --prefer-stableto CI to catch regressions before code is merged.
ShieldCI Configuration
The analyzer can be configured to enforce explicit minimum-stability declaration in composer.json.
Default Behavior (Recommended)
By default, the analyzer does NOT flag missing minimum-stability in composer.json. This assumes teams understand that Composer defaults to "stable" when the key is absent.
What's always flagged (regardless of config):
- ❌ Dangerous
minimum-stabilityvalues (dev,alpha,beta,RC) → Medium severity - ❌ Missing
prefer-stable→ Low severity - ❌ Unstable version constraints in
require→ Medium severity - ⚠️ Unstable version constraints in
require-dev(when min-stability is notstable) → Medium severity - ⚠️ Unstable version constraints in
require-dev(when min-stability isstable) → Low severity
Strict Mode (Opt-in)
For teams that want to enforce explicit configuration documentation, enable strict mode:
php artisan vendor:publish --tag=shieldci-configThen in config/shieldci.php:
'analyzers' => [
'security' => [
'enabled' => true,
'stable-dependencies' => [
'enforce_explicit_minimum_stability' => true,
],
],
],With strict mode enabled, missing minimum-stability will be flagged with Low severity:
{
"name": "my-app",
"require": {...}
// Missing "minimum-stability": "stable"
}⚠️ Warning (Low): Composer minimum-stability is not explicitly set (using implicit default "stable")
Recommendation: Teams new to Composer or with strict documentation requirements should enable this. Experienced teams comfortable with Composer defaults can leave it disabled to reduce noise.
References
Related Analyzers
- Frontend Vulnerable Dependencies Analyzer — scans npm/yarn lock files for known CVEs.
- Dependency License Compliance Analyzer — validates OSS license requirements for all dependencies.