SECURITY & COMPLIANCE · 9 MIN READ · AUGUST 30, 2026

Composer License Metadata vs. Dependency Reality: Screening 10,000 Packages

A package license only covers its author's code. We scanned 10,000 Composer packages and 100 WordPress plugins. 320 packages pulled in copyleft code while claiming a permissive license at the root, including PayPal's server SDK and WPForms Lite.

StackHal Field NotesUpdated August 30, 2026

When you install a PHP library, Composer checks version numbers. It does not check licenses. If you think an MIT tag in composer.json makes your whole app safe for business use, you are trusting a label that Composer never checks against real dependencies.

The short versionA package license only covers code written by its author. We scanned 10,000 top Composer packages and 100 top WordPress plugins. 320 packages (3.2%) pulled in copyleft code while claiming a permissive license at the root. Notable examples include PayPal's server SDK pulling OSL-3.0 code, and WPForms Lite bundling OSL-3.0 headers across 5 million active sites.

Composer does not check license compatibility

When an author puts a library on Packagist, they write a license name in composer.json. Packagist stores that text and shows it on the web page. Composer reads it when you run composer licenses.

Neither tool checks whether that license works with other packages in your tree. If an MIT package needs a GPL or OSL library, Composer still installs it without warnings. The problem stays hidden until someone audits the full tree.

audit-snapshot-2026-08-30 (top 10,000 packages)
Packagist Top 10k Screening MatrixEMPIRICAL DATA
PACKAGES AUDITED10,000Full lockfile resolution
REVIEW CANDIDATES320 (3.2%)Transitive copyleft mismatch
STRONG COPYLEFT SIGNALS184GPL, AGPL, OSL-3.0
WEAK COPYLEFT / DUAL470LGPL, MPL-2.0, Dual-GPL
Snapshot collected on August 30, 2026 across stable Packagist releases and top WordPress.org plugins.

The PayPal SDK: how OSL-3.0 reached online stores

When PayPal retired older PHP SDKs, they told merchants to use paypal/paypal-server-sdk. On Packagist, PayPal listed this package as MIT.

Looking at the real dependency tree shows a different setup:

paypal/paypal-server-sdk (Packagist says MIT | Archive contains PayPal EULA)
 \-- apimatic/core (Declared MIT | Upstream notices stripped)
      \-- apimatic/jsonmapper (SPDX: OSL-3.0 - Open Software License 3.0)
           \-- forked from cweiske/jsonmapper (Copyright Christian Weiske & Netresearch)

The issue is OSL-3.0 Section 5 ("External Deployment"). Standard GPL only triggers when you share files. OSL-3.0 treats web access as distribution:

The OSL-3.0 network trigger clause"The term 'External Deployment' means the use, distribution, or communication of the Original Work or Modifications in any way such that the Original Work or Modifications may be used by anyone other than You... shall be deemed a distribution under Section 3."

If you run an online store or SaaS app with OSL-3.0 code, users can ask for your source code. PayPal built their SDK with APIMatic tools. APIMatic used an OSL-3.0 tool from Christian Weiske. Any store using PayPal's new SDK pulled OSL-3.0 into their stack.

WPForms Lite: renaming classes does not change copyright

WordPress.org requires all hosted plugins to use GPLv2 or later compatible terms. To stop class name clashes, plugin authors often use tools like PHP-Scoper to add prefixes to third-party code.

In our scan of WPForms Lite (Rank #9 on WordPress.org, 5,000,000+ active installs), the plugin placed the APIMatic SDK in:

wp-content/plugins/wpforms-lite/vendor_prefixed/apimatic/jsonmapper/

This changed class names to WPForms\Vendor\apimatic\jsonmapper\JsonMapper, but kept the file comments. Five PHP files in that folder still hold the full Open Software License 3.0 text and copyright notices.

Prefix tools change PHP code names. They do not change license rights. Putting OSL-3.0 files inside a GPLv2 plugin creates an unresolved conflict across millions of WordPress sites.

Five libraries behind most copyleft findings

Most of the 320 flagged packages came from five upstream projects:

  • ezyang/htmlpurifier (LGPL-2.1-or-later, 108 packages): Used by frameworks like yiisoft/yii2 and tools like mews/purifier. Loading an untouched library via Composer matches LGPL dynamic linking rules, but authors often forget to include the LGPL license file and notices.
  • netresearch/jsonmapper / apimatic/jsonmapper (OSL-3.0, 27 packages): Used in code tools, JSON-RPC servers (danog/advanced-json-rpc), and Psalm plugins.
  • enshrined/svg-sanitize (GPL-2.0-or-later, 26 packages): Used by CMS plugins and shop add-ons that claim MIT terms. GPL-2.0 has no linking exception, so putting it in closed-source code creates a direct conflict.
  • paragonie/halite and hidden-string (MPL-2.0, 24 packages): Cryptography libraries. MPL-2.0 works at the file level, so you can use it in commercial apps if edits to MPL files stay open and notices stay in place.
  • dompdf/dompdf and smalot/pdfparser (LGPL-2.1 / LGPL-3.0, 20+ packages): PDF tools used in invoice makers (like horstoeko/zugferd) and Laravel wrappers (barryvdh/laravel-dompdf).

Check your vendor folder right now

You can check your dependencies from the command line:

# 1. List all licenses found in your lockfile
composer licenses --format=json

# 2. Search vendor files for copyleft headers
grep -rEi "General Public License|Open Software License|Mozilla Public License" vendor/ \
  --include="*.php" --include="*LICENSE*" --include="*NOTICE*" | head -n 30

# 3. Find why a package was installed
composer why apimatic/jsonmapper
composer why ezyang/htmlpurifier
composer why enshrined/svg-sanitize

AI agent rule: check licenses before adding code

AI coding tools often pick packages based on popularity or root tags. Give your AI agents this rule so they check lockfiles before adding new packages:

View the "composer-license-audit" Agent Skill
---
name: composer-license-audit
description: Screen Composer dependencies for license metadata and copyleft signals before recommending packages.
---

# Composer License Compliance Skill

## Rules
1. Always check exact versions in composer.lock. Treat composer.json lookups as unpinned estimates.
2. Trace all child dependencies to find copyleft licenses (GPL, AGPL, OSL, LGPL, MPL) before picking packages.
3. Look for LICENSE files, NOTICE files, and code header comments in vendored or prefixed code.
4. Separate file-level weak copyleft (MPL, LGPL) from network-triggered strong copyleft (OSL-3.0, AGPL).
5. Never assume a root MIT or BSD tag covers the full dependency tree.

## Output
- State if data came from composer.lock or unpinned Packagist lookups.
- Report full dependency paths for any flagged licenses (e.g. root -> depA -> depB [OSL-3.0]).
- Note if libraries are autoloaded or bundled directly.

Full data and tools

The full dataset of 10,000 packages, edge tables, WordPress logs, and scripts are open in the StackHal repository under docs/research/composer-license-audit/.

Sources and links: Composer Lock Documentation | OSI Open Software License 3.0 | WordPress.org Plugin Guidelines | StackHal Research Dataset