You ask your AI agent to solve a PDF generation problem. Five minutes later, it has installed pandoc (GPL-2.0), pulled a WASM-based converter with ambiguous licensing, and resolved a dependency from an unofficial mirror. The problem is solved. The code works.
But now your project has a GPL dependency, a WASM binary whose license doesn't match its JavaScript wrapper, and a binary downloaded from a source with no integrity guarantees. The agent didn't check any of this. It wasn't built to.
I've run into this more than once while working on commercial products. Packages like these show up in your dependency tree without any friction, and by the time someone notices, the code is already in production. This post is what I wish I'd had before that happened — a practical guide to catching these issues early and automating the check so you don't have to think about it.
⚡ How It Happens
AI coding agents optimize for solving the problem you described. They search npm, crates.io, PyPI, GitHub — whatever produces a working solution fastest. What they don't do:
- Read the
licensefield inpackage.json - Distinguish between MIT and GPL
- Know that your project is a commercial product
- Check if a
.wasmbinary was compiled from GPL source code - Verify that a mirror is official or trusted
There's no malice here. The agent is simply indifferent to licensing. And when you're moving fast with AI-assisted development, that indifference compounds quietly.
🔍 Four Risks Worth Knowing
1. GPL/AGPL Contamination
GPL is a copyleft license. If your project links against a GPL dependency, your project must also be distributed under GPL — or you can't distribute it at all. AGPL extends this to network use: if users interact with your software over a network (i.e., most SaaS products), you must provide source code.
This isn't just about direct dependencies. If package A is MIT but depends on package B which is GPL, the GPL propagates up the tree.
Known examples: pandoc (GPL-2.0), ghostscript (AGPL-3.0), ffmpeg (GPL-2.0+ depending on build flags).
2. No License = No Permission
A common misconception: if a package has no license, it's free to use. Under copyright law, it's the opposite — no license means all rights reserved. You have no legal permission to use, copy, or distribute it.
npm packages with an empty license field, or with "UNLICENSED" in package.json, fall into this category. The agent installs them just like any other package.
3. WASM Binaries — The Black Box
An npm package can have a MIT-licensed JavaScript wrapper around a .wasm binary compiled from C, C++, or Rust source code. The binary inherits the license of its source code, not the wrapper.
svg2pdf-wasm illustrates this well: the npm package may declare one license, but the compiled binary comes from a Rust crate with its own licensing terms. The agent only reads package.json. It never checks the binary's provenance.
4. Unofficial Mirrors and Supply Chain
When an agent resolves dependencies, it may pull from non-standard sources — unofficial mirrors, npm proxies, or GitHub forks of abandoned packages. These aren't necessarily malicious, but they bypass the integrity guarantees of official registries.
Some packages also run postinstall scripts that download additional binaries at install time. The npm package might be MIT, but the binary it fetches could have entirely different terms.
| Risk | Red flag | Impact |
|---|---|---|
| GPL in commercial project |
license: GPL-* or AGPL-* in package.json |
Must open-source your code or stop distributing |
| No license | Missing or UNLICENSED license field |
No legal permission to use |
| WASM license mismatch |
.wasm files in node_modules |
Binary license ≠ wrapper license |
| Unofficial source | Non-standard URLs in postinstall scripts |
No integrity guarantees |
🛠️ The Solo Dev Recipe
Three checks before you deploy. No extra dependencies — just your package manager and standard shell tools.
Step 1: List All Licenses
pnpm has a built-in command for this:
pnpm licenses list --prod
npm doesn't have a native equivalent, but every package.json has a license field. You can extract them all:
find node_modules -maxdepth 2 -name "package.json" -exec \
jq -r '[.name, .version, .license // "NONE"] | @tsv' {} \; 2>/dev/null \
| sort
This gives you a complete list: package name, version, and license. Look for anything that isn't MIT, ISC, BSD, or Apache.
Step 2: Find Problematic Licenses
Filter for GPL, AGPL, or packages with no license at all:
# GPL/AGPL dependencies
pnpm licenses list --prod 2>/dev/null | grep -iE "GPL|AGPL"
# Packages with no license field
find node_modules -maxdepth 2 -name "package.json" -exec \
jq -r 'select(.license == null or .license == "" or .license == "UNLICENSED") | .name' {} \; 2>/dev/null
If either of these returns results, stop and investigate before shipping.
Step 3: Find WASM Binaries and Postinstall Scripts
These are supply chain concerns that no license field will tell you about:
# WASM binaries in your dependencies
find node_modules -name "*.wasm" 2>/dev/null
# Packages with postinstall scripts (can download arbitrary binaries)
find node_modules -maxdepth 2 -name "package.json" -exec \
jq -r 'select(.scripts.postinstall != null) | "\(.name): \(.scripts.postinstall)"' {} \; 2>/dev/null
If you find .wasm files, check the source repository. The npm package license is not authoritative for compiled binaries — the binary inherits the license of the code it was compiled from.
Putting It Together
A single script that covers all three checks:
#!/bin/bash
# license-audit.sh — zero dependencies, just shell + jq
set -euo pipefail
BLOCKED="GPL\|AGPL\|SSPL"
EXIT_CODE=0
echo "── License audit ──"
PROBLEMS=$(pnpm licenses list --prod 2>/dev/null | grep -iE "$BLOCKED" || true)
if [ -n "$PROBLEMS" ]; then
echo "Copyleft licenses found:"
echo "$PROBLEMS"
EXIT_CODE=1
fi
echo "── Missing licenses ──"
MISSING=$(find node_modules -maxdepth 2 -name "package.json" -exec \
jq -r 'select(.license == null or .license == "" or .license == "UNLICENSED") | .name' {} \; 2>/dev/null)
if [ -n "$MISSING" ]; then
echo "Packages with no license:"
echo "$MISSING"
EXIT_CODE=1
fi
echo "── WASM binaries ──"
WASM=$(find node_modules -name "*.wasm" 2>/dev/null)
if [ -n "$WASM" ]; then
echo "Found (verify source licenses manually):"
echo "$WASM"
fi
echo "── Postinstall scripts ──"
POSTINSTALL=$(find node_modules -maxdepth 2 -name "package.json" -exec \
jq -r 'select(.scripts.postinstall != null) | "\(.name): \(.scripts.postinstall)"' {} \; 2>/dev/null)
if [ -n "$POSTINSTALL" ]; then
echo "Packages with postinstall:"
echo "$POSTINSTALL"
fi
exit $EXIT_CODE
Drop this in your repo as scripts/license-audit.sh, run it before deploys or in CI. It uses pnpm, jq, find, and grep — tools that are already on your machine.
🏗️ Scaling to Teams: A Claude Code Hook
The script above works for one developer. In a team with multiple AI agents running in parallel, manual checks don't hold up. You need something automatic.
A Claude Code PostToolUse hook that runs after every package install:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash -c 'if echo \"$TOOL_INPUT\" | grep -qE \"(npm install|pnpm add|pnpm install|yarn add)\"; then pnpm licenses list --prod 2>/dev/null | grep -iE \"GPL|AGPL\" && echo \"⚠ Copyleft license detected\" || true; fi'"
}
]
}
]
}
}
Every time the agent runs pnpm add, npm install, or yarn add, this hook checks for copyleft licenses. If something problematic slipped in, the agent sees it right away.
This goes in your project's .claude/settings.json or your global ~/.claude/settings.json.
A Prompt-Based Alternative
For a more contextual approach, a prompt-based hook gives the agent enough information to reason about the problem and suggest alternatives:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "prompt",
"prompt": "If the command just executed was a package install (npm install, pnpm add, yarn add), check for license issues: run `pnpm licenses list --prod 2>/dev/null | grep -iE 'GPL|AGPL'` and `find node_modules -name '*.wasm' 2>/dev/null`. If you find GPL/AGPL dependencies, identify them and suggest MIT/Apache-licensed alternatives. If you find WASM binaries, flag them and note that their license may differ from the npm package license."
}
]
}
]
}
}
With this version, the agent doesn't just detect the problem — it looks for alternatives and explains the licensing concern.
🔒 Going Further: A License Audit Skill
For teams that want structured coverage, a dedicated Claude Code skill can encode your license policy, know your project type, and guide the agent through every install decision.
I'm publishing a reference implementation as a Claude Code skill: license-audit-skill.
What it includes:
- License policy configuration — allowed/blocked licenses per project type (MIT, Apache, commercial SaaS)
- Progressive disclosure — lightweight context by default; deep reference files (compatibility matrix, WASM audit guide) load only when needed
- PostToolUse hook — automatic check after every package install, using only native tools
-
WASM binary audit — finds
.wasmfiles and traces them to their source license -
Supply chain checks — flags
postinstallscripts that download external binaries - Alternative suggestions — when a package is blocked, helps the agent find a permissively-licensed replacement
The whole thing runs on pnpm, jq, find, and grep. No license-checker packages that themselves go unmaintained — which would be ironic in an article about dependency risk.
📋 TL;DR
| Who | What to do | Tool |
|---|---|---|
| Solo dev | Run pnpm licenses list --prod and check for GPL/AGPL |
Built-in |
| Team with AI agents | Add a PostToolUse hook to .claude/settings.json
|
Automatic on every install |
| Commercial product |
license-audit.sh in CI + prompt-based hook |
Shell script, zero dependencies |
| Risk level | License types | Action |
|---|---|---|
| 🟢 Safe | MIT, ISC, BSD-2, BSD-3, Apache-2.0, 0BSD | Use freely |
| 🟡 Review | LGPL-2.1, LGPL-3.0, MPL-2.0, CC-BY-4.0 | Check your linking and distribution model |
| 🔴 Blocked | GPL-2.0, GPL-3.0, AGPL-3.0, SSPL, UNLICENSED | Don't use in commercial/closed-source without legal review |
Your agent writes the code. You own the license. Know what's in your dependencies before someone else asks.
Originally published on augustochirico.dev
Top comments (0)