Skip to content
PHP supply chain

PHP supply chain: scan 6,000+ advisories every night

Paste a composer.json or composer.lock and get in thirty seconds a security-first audit of the manifest: active CVEs on installed versions (with CVSS vector and CWE IDs), abandoned packages with suggested replacement, end-of-life frameworks with security support end date, PHP constraint audit, detection of wildcard constraints, dev-branch dependencies, non-Packagist repositories, enabled Composer plugins. Dataset of 6,000+ advisories recompiled nightly from Packagist Security API, OSV.dev and endoflife.date. The analysis runs entirely in the browser: your manifest never leaves the page.

Drop a composer.json or composer.lock here, or click to select a file (max 5 MB)

How to use the audit

  1. 1

    Get composer.json or composer.lock

    Both files live at the project root, next to vendor/. composer.json declares dependencies and version constraints (e.g. "laravel/framework": "^11.0"): it is committed to git and visible on the repository (GitHub, GitLab, Bitbucket). composer.lock is generated by composer install/update and contains the exact resolved versions (e.g. 11.5.0) plus integrity hashes: it is also committed to git to guarantee deterministic builds between dev and production. For an accurate audit prefer the composer.lock: the manifest declares what is allowed, the lock declares what was actually installed.

  2. 2

    Paste in the tool

    The tool auto-detects the type: a top-level packages array identifies the lock, a require object with string constraints identifies the json. JSON parsing is strict: syntax errors fail with explicit diagnostic. Input never leaves the browser: no network request carries your manifest, the analysis runs entirely in local JavaScript against a static dataset preloaded from the site.

  3. 3

    Read the report

    Two-tier output. Statistics: total package count, require / require-dev breakdown, PHP constraint, required extensions. Severity-ordered findings (critical, high, medium, low, info): for every issue you get the affected package, motivation, link to the public CVE record (cve.org) or to the GitHub Security Advisory (GHSA), CVSS vector when available, list of associated CWEs, vulnerable constraints and installed version, remediation hint. At the top: aggregated score 0-100 (green above 80, yellow 50-80, red below 50).

  4. 4

    Then run the real audit (CLI)

    Static triage in the browser gives you a snapshot today. To integrate into pipelines and block future regressions: composer audit from terminal (official command since Composer 2.4, September 2022) compares installed packages against the FriendsOfPHP CVE database. composer require --dev roave/security-advisories:dev-latest adds a meta-package that blocks installation of packages with known CVEs (zero runtime overhead, only conflict declarations). Best practice: composer audit --abandoned=report inside the test job of your CI/CD, exit code != 0 if active CVEs are found.

Known vulnerabilities, EOL, abandoned: the three real PHP supply chain risks

PHP applications don't die of old age, they die of skipped maintenance. In every uncared-for Composer project three things happen silently: new CVEs get published against the actually-installed versions, authors stop maintaining libraries and mark packages as abandoned, major framework branches drop out of security support. After eighteen-twentyfour months of immobility, the application formally works but is exposed to vulnerabilities that have been known and patched in newer versions. This tool surfaces that state in thirty seconds from the manifest alone.

What the audit actually checks. Three independent sources feed the triage. (1) Known vulnerabilities (CVE): the Packagist Security Advisory API aggregates FriendsOfPHP/security-advisories and the GitHub Advisory DB; OSV.dev (Open Source Vulnerabilities, maintained by Google) enriches each advisory with CVSS v3 vector and CWE IDs. Coverage: 6,000+ advisories on 1,000+ Composer packages. (2) End-of-life (EOL): endoflife.date publishes the release cycles of the main frameworks with end-of-security-support dates. Monitored: PHP, Laravel (and illuminate/*), Symfony (and every symfony/*), Composer itself, Guzzle, Twig, CakePHP, Drupal, GrumPHP. (3) Abandoned: the abandoned flag from Packagist is read for the union of all packages mentioned in advisories and the top 2,000 popular packages, with a 7-day cache TTL. Result: 210+ packages flagged as actually abandoned in the dataset.

Difference between auditing the lock and auditing the json. The composer.lock contains exact resolved versions: the matcher does an exact lookup against the advisory's affected interval (e.g. >=9.0.0,<9.5.6). The composer.json contains only the declared constraint (e.g. ^9.0): the matcher computes the intersection between the user constraint and the affected interval, flagging if any installable version is vulnerable. For rigorous audits use the lock. The json is useful to assess whether the constraint would permit downloading vulnerable versions on a fresh composer install tomorrow: triage flags it, but truth lives in production.

The constraint matcher is precise. It does not stop at major-version comparison: it implements caret ^X.Y.Z with the major-zero exception (^0.5.0 = >=0.5.0 <0.6.0, ^0.0.5 = >=0.0.5 <0.0.6), tilde ~X.Y, wildcard X.Y.*, hyphen range 1.0 - 2.0, operators >= <= > < =, OR || and AND comma-or-whitespace, stability suffixes -dev -alpha -beta -RC with lexicographic priority. Normalization is in DNF (disjunctive normal form) of intervals and constraint-vs-constraint intersection is pairwise overlap: same semantics as composer/semver PHP, in vanilla JS, with no dependencies.

Operational privacy. The composer.lock reveals the full structure of a project, its transitive dependencies, and any private packages with references to internal VCS repositories. Uploading it to a third-party service for preliminary analysis is not a good idea, even over TLS: every third party is a leak vector for your dependency map. Here no request leaves with manifest data. The dataset (16 advisory shards + 1 EOL file + 1 abandoned file) is downloaded by the browser only on first use and cached in localStorage for subsequent sessions (automatic invalidation via SHA-256 over the public files). Audit, parsing, matching: all local.

When static triage is the right level. Typical scenarios. (a) Preliminary review of a legacy project without filesystem access: the client pastes the manifest in an email and wants an assessment in thirty seconds. (b) Pre-engagement audit to estimate the cost of a possible remediation contract before quoting. (c) Initial screen before a serious cyber assessment: define the list of high/critical to deepen with exploitability assessment, mapping of applicable vectors, reachability of the codepaths. (d) Periodic self-check by the application owner who wants to know whether the maintainer is doing the work.

Scope limit. The tool flags published CVEs, known EOL, declared abandonment. It does not replace enterprise Software Composition Analysis (Snyk, Mend, Sonatype): no license check, no SBOM CycloneDX generation, no analysis of non-Composer code (system binaries, Node scripts, container base images). It does not replace composer audit CLI integrated into pipelines. It does not replace a manual assessment that evaluates real exploitability of vectors, presence of codepaths in installed versions, mitigations applied at hardening level. It is a triage and presents itself as one.

What the tool checks, in detail

The dataset is structured into three independent components, all published as static files under /tools/resources/data/composer-audit/, recompiled nightly by a cron job and versioned by SHA-256 in the index.json.

Advisories (6,000+ across 1,000+ packages). Primary source: Packagist Security Advisory API, which aggregates FriendsOfPHP/security-advisories (collaborative YAML database) and the GitHub Security Advisories relevant to the Composer ecosystem. Enrichment source: OSV.dev, full Packagist dump, from which we extract for each advisory the CVSS v3 vector and the CWE identifiers. For each finding: Packagist id, cve, ghsa, declared severity, CVSS, CWE list, affected constraints (e.g. >=5.4.0,<5.4.50|>=6.0.0,<6.4.18|>=7.0.0,<7.1.11), reporting date. The payload is sharded into 16 files by the first hex nibble of SHA-1 over the package name: the browser only loads the shards for packages actually present in the manifest, not the entire dataset.

End-of-life (9 products, 133 cycles). Source: endoflife.date via API /api/{product}.json. For each cycle: end-of-security-support date, LTS flag, latest patch release. The client computes status by comparing eol_date with today: eol if past, soon-eol if within 180 days, lts/current otherwise. Monitored packages: PHP (manifest constraint), laravel/framework and every illuminate/*, symfony/symfony and every symfony/* standalone, composer/composer, guzzlehttp/guzzle, twig/twig, cakephp/cakephp, drupal/core, phpro/grumphp. endoflife.date covers only frameworks and tools with public cycles: single libraries like PHPUnit, Doctrine, Monolog, Flysystem, PHPStan, Carbon have no published EOL and are covered by CVE and abandoned signals.

Abandoned (210+ actually abandoned out of 2,800 checked). Coverage strategy: union(A,B) where A is the set of packages mentioned in advisories (~1,000) and B is the list of top 2,000 Packagist packages by popularity. For each name: GET https://packagist.org/packages/{vendor}/{name}.json and read the abandoned field (boolean true or string with the suggested replacement). Disk cache with 7-day TTL to avoid pointless re-fetching at steady state: at steady state each cron run costs 30 seconds versus the 4 minutes of the cold bootstrap. The client only receives the actually-abandoned packages, not the full checked list.

Atomic publication. The cron job applies an atomic multi-file write: all new shards are written to temporary files, renamed one by one, and the index.json with the new SHA-256 values is the last file renamed. If the process dies mid-way, clients keep reading the previous dataset via the not-yet-updated index.json. Never partial dataset, never index/shard mismatch. If even one of the three sources (Packagist, OSV, endoflife) fails, the job aborts without publishing: better a one-day-old dataset than an incomplete one.

How to read a report

Aggregated score 0-100. Computed as 100 - sum(severity_weights), where weights are: critical 30, high 15, medium 7, low 3, info 1. Reading: 80-100 green (reasonable supply chain posture), 50-79 yellow (interventions plannable in upcoming sprints), 0-49 red (significant technical debt, some interventions need immediate mitigation). The score is not a general software-quality metric: it only measures manifest health from the perspective of vulnerabilities, EOL and abandonment.

Finding severity. critical: vulnerability with CVSS >= 9.0 or Packagist severity critical, typically unauthenticated RCE, direct SQL injection, unsafe deserialization. high: CVSS 7.0-8.9 or high severity, or EOL package with historical CVE, or abandoned package in production. medium: CVSS 4.0-6.9, PHP constraint nearing EOL, dev-branch dependencies. low: CVSS 1.0-3.9, unspecified PHP constraint, non-Packagist repository with low-risk type (composer mirror, github). info: operational recommendations (roave/security-advisories not installed, enabled Composer plugins, custom VCS repositories). Findings are sorted from highest to lowest severity inside the results block.

What to do, by priority. (1) For every critical: upgrade immediately to the fixed version stated in the CVE record, or document in writing why the vector is not applicable to the specific codepath (e.g. feature not used, mitigation applied elsewhere). Do not defer. (2) For every high: plan upgrade within the current sprint. If the package is abandoned, replace with the suggested replacement or with a maintained fork. If the framework is EOL, evaluate the cost of upgrading to current or LTS branch. (3) For medium and low: quarterly hardening backlog, incremental refactor of the manifest toward stricter constraints (^X.Y minimum, never *), removal of dev-branch dependencies in favor of stable tags. (4) For info: add roave/security-advisories:dev-latest as dev dependency, run composer audit in CI/CD, periodic audit of Composer plugins enabled via allow-plugins.

CVE finding format. Each CVE finding shows installed version, identifiers (CVE, GHSA), CVSS vector when available, CWE list, exact affected constraint. The link in the References field points to the CVE Record (cve.org) or to the GitHub Advisory: there you find technical description, public exploits if documented, exact fixed version, and the upstream patch commit. To pass to the team with the operational message: upgrade to fixed version within X days, or produce a written analysis of vector reachability in the application code.

Data sources and monitored packages

The tool consumes a static dataset recompiled daily by shared/cron/build_composer_audit_db.php. Three independent sources feed the triage:

  • Advisories (Packagist Security API + OSV.dev): 6,000+ advisories across 1,000+ Composer packages, enriched with CVSS vector and CWE IDs from the OSV database. Coverage is independent of package popularity.
  • EOL (endoflife.date): frameworks and tools with public release cycles. Monitored: php, laravel/framework (and illuminate/*), symfony/symfony (and every symfony/*), composer/composer, guzzlehttp/guzzle, twig/twig, cakephp/cakephp, drupal/core, phpro/grumphp. For each branch: end-of-security-support date and status (current / lts / soon-eol / eol).
  • Abandoned (Packagist): abandoned flag read from Packagist for the union of (a) all packages mentioned in advisories and (b) the top 2,000 Composer packages by popularity. ~2,800 unique packages checked per cycle, 7-day cache TTL.

Libraries not covered by EOL (PHPUnit, Doctrine, Monolog, Flysystem, PHPStan, Carbon, etc.) remain monitored via CVE and abandoned signals: endoflife.date only tracks frameworks/CMS, individual Composer libraries have no equivalent public EOL cycle.

Glossary

Technical terms used on this page, briefly explained.

composer.json #
PHP project manifest file. Declares name, author, dependencies (require, require-dev), version constraints (e.g. ^11.0), PSR-4 autoload. Committed to git, it is the authoritative document on what the project declares it wants to install.
composer.lock #
File auto-generated by composer install/update. Contains exact resolved versions of every package + content-hash + timestamp. Guarantees deterministic builds between dev and production. Committed to git (best practice). For precise security audits it is the authoritative source: the manifest says what is allowed, the lock says what is actually installed.
Composer version constraint #
Syntax to declare which versions of a dependency are acceptable. ^1.2 = SemVer compatible (>=1.2 <2.0, special-cased for major 0). ~1.2.3 = patch-level (>=1.2.3 <1.3.0). 1.2.* = wildcard. >=1.2,<1.5 = AND of operators. ^1.0 || ^2.0 = OR of ranges. 1.0 - 2.0 = hyphen range. Best practice: ^X.Y for stable dependencies, ~X.Y.Z for conservative dependencies where you only want patches.
CVE (Common Vulnerabilities and Exposures) #
Unique identifier of a public vulnerability in the form CVE-YYYY-NNNN. Assigned by the responsible CVE Numbering Authority (CNA). Authoritative database: cve.org. Every CVE relevant to the Composer ecosystem maps to Packagist Security and/or GitHub Advisory.
CVSS (Common Vulnerability Scoring System) #
Standard system for scoring CVE severity. Current version: 3.1 (4.0 in progressive adoption). Output: vector string (e.g. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) and base score 0.0-10.0. Severity bands: 0.1-3.9 low, 4.0-6.9 medium, 7.0-8.9 high, 9.0-10.0 critical.
CWE (Common Weakness Enumeration) #
Taxonomy of software weakness classes. Identifiers in the form CWE-NNN (e.g. CWE-79 Cross-Site Scripting, CWE-89 SQL Injection, CWE-502 Deserialization of Untrusted Data, CWE-200 Information Disclosure). A CVE may have multiple CWEs associated. Useful for pattern matching during review and for team training.
GHSA (GitHub Security Advisory) #
GitHub-native security advisory identifier, format GHSA-xxxx-xxxx-xxxx. GitHub maintains a database parallel to CVE with often faster triage for open source ecosystems. Each GHSA can map to a published CVE (mapping exposed in the advisory's cve field).
PSA (Packagist Security Advisory) #
Packagist identifier in the format PKSA-xxxx-xxxx-xxxx. Packagist aggregates FriendsOfPHP/security-advisories and Composer-relevant GHSAs into a unified API endpoint.
EOL (End Of Life) #
Date beyond which a package or framework no longer receives security updates. Keeping EOL components in production is a risk: new vulnerabilities are not patched on the branch and the only path is the upgrade. In NIS2 scope (art. 21(2)(g)) this is explicitly flagged as 'inadequate cyber hygiene'.
LTS (Long Term Support) #
Branch of a framework or language that receives security updates for an extended period (typically 2-5 years) even after the next version is released. Examples: historical Laravel LTS (5.5, 6.x), Symfony LTS (4.4, 5.4, 6.4), PHP has no formal LTS but every minor receives security updates for about 2 years.
Abandoned #
State declared by the maintainer in composer.json with the abandoned field (boolean true or string with the suggested replacement name). Packagist exposes this flag in the package's public JSON. Not to be confused with deprecated: a deprecated package is still maintained but replaced by a newer version, an abandoned package is declared out of maintenance by its author.
FriendsOfPHP/security-advisories #
Collaborative open source database of security advisories for Composer packages. Updated daily, YAML format, GitHub repository. Historical basis of the roave/security-advisories meta-package and of the Packagist Security Advisory API.
OSV.dev #
Open Source Vulnerabilities, database maintained by Google. Unified OSV schema, bulk dump per ecosystem (Packagist, npm, PyPI, Go, Maven, etc.). For each vulnerability: aliasing between CVE/GHSA, CVSS v3 severity, CWE IDs, affected ranges per package version. Enrichment source for this tool's dataset.
endoflife.date #
Open source database of release cycles for languages, frameworks, runtimes and tools. Public JSON API at /api/{product}.json. For each cycle: release date, end of active support, end of security support, LTS flag, latest patch release. Source of this tool's EOL dataset.
roave/security-advisories #
Composer meta-package (no code, just conflict declarations) that blocks installation of packages with known CVEs. Usage pattern: composer require --dev roave/security-advisories:dev-latest. Zero runtime overhead, zero impact on build size: conflicts are evaluated only at the dependency manager solve time.
composer audit #
Official Composer command available since 2.4 (September 2022). Compares installed packages against the Packagist Security CVE database and produces text or JSON output. Exit code != 0 if active CVEs are present. To integrate in CI/CD test jobs to block PRs that introduce security regressions.
Renovate / Dependabot #
Automated bots (native GitHub Dependabot, multi-platform Renovate Bot) that monitor dependencies and open update PRs. For PHP-Composer: native support, recognize security advisories and prioritize security PRs separately from minor/patch updates.
Supply chain security #
ICT security discipline focused on third-party dependencies: open source libraries, package registries, mirrors, build runners, deploy artifacts. NIS2 scope (art. 21(2)(d)) explicitly includes ICT supply chain as a risk-management subject. Operational tools: SBOM (Software Bill of Materials), deploy signing, continuous CVE monitoring, update policies with SLAs.

Frequently asked questions about Composer audit

I'm the owner or project manager of a PHP application, not a developer. Do I really need this tool?
Yes, and you are in fact one of the targets. The tool's logic is written to be readable without deep PHP knowledge: for every finding you get severity (critical, high, medium, low, informational), affected package name, explicit motivation, link to the public CVE or GitHub Advisory. If the report returns more than three or four high or critical findings on production dependencies, you have a concrete argument to bring to the development team and ask how and when the application will be updated.
Where do I actually find the composer.json or composer.lock of my application?
Both live at the project root, next to the vendor/ folder. Three typical retrieval paths. (1) Git repository: ask for access to the repository (GitHub, GitLab, Bitbucket) and you find them at the root, they are committed text files. (2) Production server: with SSH access they live at /var/www/<project-name>/composer.json or similar. (3) Shared hosting: usually accessible via FTP/SFTP or control panel. In no case do these files contain sensitive application data (users, passwords, transactions): they only contain the library list and their versions.
The report flags a package as EOL and my developer says 'it's not urgent'. How do I respond?
EOL means the maintainer DOES NOT release security updates on the branch in use. New vulnerabilities are not patched for that version. It is not a subjective estimate: it is a public date. The correct answer from a competent developer is 'I'm planning the upgrade by date X' or 'the vector is not applicable to our scenario because of Y, and I document it in writing', not 'it's not urgent'. In NIS2 scope (art. 21(2)(g), enacted in Italy through Legislative Decree 138/2024) keeping EOL components in production is explicitly treated as a signal of inadequate cyber hygiene.
Difference between auditing the lock and auditing the json?
The composer.lock contains the exact resolved versions: the tool knows you installed exactly 9.5.10 and can tell you whether that specific version is affected by a CVE. The composer.json contains only declared constraints (^9.0): the tool does not know the actual version, but it can tell you whether the constraint would permit installing vulnerable versions. For precise audits with immediate operational value use the lock; the json is useful to assess whether a fresh composer install tomorrow could pull affected versions.
Does the tool flag specific CVEs per package?
Yes. The dataset fed by Packagist Security API + OSV.dev contains 6,000+ published advisories with CVE identifier when assigned, GitHub Security Advisory (GHSA), severity, CVSS v3 vector when enriched by OSV, associated CWE list, exact affected constraint. For every match: direct link to the CVE Record or GitHub Advisory page. The dataset is recompiled nightly to stay aligned with new publications.
Is the version matching precise or just approximate?
Precise on the lock. The ComposerSemver module implements the same semantics as composer/semver PHP: caret, tilde, wildcard, hyphen range, OR/AND, stability suffix, major-zero exception. On the lock it does exact lookup (concrete version vs affected interval). On the json it computes intersection of intervals normalized in DNF: a finding is emitted when at least one installable version is covered both by the declared constraint and by the vulnerable interval. The module is validated by a 44-fixture test suite (manually runnable from console: ComposerSemver.runFixtures()).
How many packages can I audit at once? Performance?
Performance is OK up to 1,000 packages in a single audit. The dominant cost is the advisory shard fetch (up to 16 files of ~100 KB each, gzipped to ~25 KB). With a warm cache the audit is instant (parsing + matching on a few hundred packages = milliseconds). For enterprise projects with 1,000+ deps: composer audit CLI is faster and more accurate (reads vendor/composer/installed.json directly). Our tool is optimized for typical projects between 30 and 300 deps, the 80% of consulting/SMB projects.
What happens with a package not in the dataset?
It's counted in the general statistics but produces no finding. Unknown to the dataset does not mean dangerous: most Composer packages are niche or private and have never been the subject of a public advisory, published EOL or abandoned flag. For wider coverage on niche packages: composer audit CLI reads the full FriendsOfPHP CVE database, and Snyk/Dependabot integrated in the repository monitor continuously.
The project's PHP constraint is <code>>=7.4</code>. What does the tool flag?
It's flagged as php_eol: the constraint includes PHP 7.4 (security support ended 2022-11), 8.0 (ended 2023-11), 8.1 (ended 2025-12). It means composer install would formally accept installation on a PHP 7.4 machine even if production reality is 8.x. Best practice: >=8.2 minimum in the constraint, regardless of the current production version. Communicates intent + prevents accidental installs on legacy VPS + is a cyber hygiene signal for external audits.
Symfony has many standalone components (<code>symfony/console</code>, <code>symfony/yaml</code>, etc.). Are they all covered?
Yes. The tool considers every symfony/* package with the same LTS policy as the main release (Symfony 5.4 LTS = symfony/console:5.4 LTS, etc.). The mapping is via symfony/ prefix in the product_prefixes of eol.json. Same pattern for illuminate/* mapped to the Laravel cycle. Rare exceptions (components with cycles slightly different from the main release) are not modeled to avoid false positives on marginal corner cases.
Does the tool integrate any external PHP/JS library at runtime?
No. JSON parse is native, the constraint matcher is the composer-semver.js module written from scratch, dataset fetch uses the native fetch API, sharding uses native crypto.subtle.digest('SHA-1'). Zero dependencies, total ~13 KB of JavaScript (3 KB minified gzip for semver, 10 KB gzip for the GUI). The dataset itself is static, recompiled by the server-side PHP cron: the browser only downloads the shards needed for the manifest's packages, not the entire dataset.
Difference between abandoned, deprecated and EOL?
Abandoned: the maintainer has explicitly marked the package as abandoned in composer.json (abandoned field read from Packagist). Deprecated: the package is still maintained but replaced by a newer version (e.g. league/flysystem 1.x deprecated in favor of 2.x). EOL: the maintainer no longer releases security updates on the branch (e.g. Symfony 5.4 after November 2025). All three require migration planning; abandoned and EOL on production branches are the most urgent.
Can I use the tool on a library's composer.json, not an application's?
Yes, it works the same. Libraries typically have fewer packages (10-30) and are more conservative on backwards compatibility. Typical library findings: too-permissive PHP constraint (>=7.0 to support legacy downstream), version pinning of EOL test frameworks, dependencies on old abandoned doctrine/cache. Useful audit before publishing a new major release or closing the scope of a long-term version.
How do I integrate the real audit into CI/CD?
GitLab CI: composer audit --abandoned=report --format=json in the test job, exit code != 0 fails the merge. GitHub Actions: same command, optionally with tj-actions/composer-audit action. Pre-commit hook: composer audit in .husky/pre-commit or .git/hooks/pre-commit. Best practice: also run the audit on release tags, not only on PRs, to catch CVEs published between merge and deploy. To block install of vulnerable packages: composer require --dev roave/security-advisories:dev-latest.
Is the dataset updated in real time?
Almost: the cron recompiles it nightly at 03:00 UTC. Typical latency between a new CVE published on Packagist and visibility in the tool: less than 24 hours. For zero latency you need composer audit CLI integrated into the pipeline, which queries the Packagist API at execution time. The choice of nightly rebuild is a trade-off between freshness and network cost (the job makes ~2,800 Packagist calls at steady state).
Privacy: is the manifest I paste stored or tracked?
No. The tool runs entirely in the browser. The only outgoing network request is the GET of the static dataset files, identical for every user, fully anonymous. The pasted composer.json or composer.lock is never sent in any network request, never saved in localStorage, never tracked in analytics. You can verify by opening the DevTools Network panel during the audit: zero outgoing requests with manifest data.

Does your PHP project's supply chain hold up under a serious audit?

This tool is a static triage: it surfaces published CVEs, known EOL and declared abandonment visible from the manifest alone. A professional review examines the full chain: dependency inventory (direct and transitive), continuous CVE monitoring via Dependabot or Renovate, severity-based update policies with SLAs, CI/CD pipeline hardening, deploy signing, NIS2 supply chain scope (art. 21(2)(d)), exploitability assessment of vectors against actually-reachable codepaths. If the triage above showed a list you didn't expect, the problem already exists: the next step is understanding real priorities, costs and timelines of remediation. I work on Laravel, Symfony and custom PHP backends with 10+ years of focus on production applications and regulatory adaptation.

PHP supply chain audit

Want a realistic estimate for your project?

7-question wizard, 2 minutes, free. Output: range of person-days, rough price range, engagement recommendation. Reference rate 300 EUR/day. Built for custom backend projects, integrations, security audits or AI automation.

Get a free quote