pubguardian scans your Dart and Flutter project's dependencies for security vulnerabilities, bad licenses, abandoned packages, and risky version constraints — all from a single command.
Run it locally before a release, or drop it into CI to block on findings.
| Check | What triggers it |
|---|---|
| CVEs | Your locked packages matched against the OSV.dev advisory database |
| Bad licenses | GPL, AGPL, SSPL (and more, depending on your policy) |
| Abandoned packages | No pub.dev release in over a year |
| Discontinued packages | Publisher officially marked it discontinued |
| Risky constraints | any, *, open-ended >=x.y.z, pre-1.0 carets |
Install globally and run it from your project root:
dart pub global activate pubguardian
pubguardian scanThat's it. It reads your pubspec.lock and pubspec.yaml automatically.
Make sure the global
bindirectory is in yourPATH:
macOS / Linux (bash, zsh):
export PATH="$PATH:$HOME/.pub-cache/bin"Windows (PowerShell):
$env:Path += ";$env:LOCALAPPDATA\Pub\Cache\bin"Windows (cmd):
setx PATH "%PATH%;%LOCALAPPDATA%\Pub\Cache\bin"pubguardian — my_app 1.0.0
────────────────────────────────────────────────────────────────
CVE / Advisory Findings
────────────────────────────────────────────────────────────────
http 0.13.0 (direct)
[CRITICAL] GHSA-4rgh-jx4f-qfcq · CVE-2024-12345
Request smuggling via malformed headers
Fix: upgrade to 0.13.6 or later
https://osv.dev/vulnerability/GHSA-4rgh-jx4f-qfcq
License Compliance Findings
────────────────────────────────────────────────────────────────
some_gpl_package 2.0.0 (transitive)
[STRONG-COPYLEFT] GPL-3.0-only
Requires derivative works to also be licensed as GPL-3.0-only.
Package Health Findings
────────────────────────────────────────────────────────────────
✖ flutter_legacy 0.3.0
Package is officially discontinued. Replacement: flutter_new.
⚠ old_helper 1.2.0
No release in 847 days (2.3 years). Latest on pub.dev: 1.2.0.
Constraint Warnings
────────────────────────────────────────────────────────────────
[HIGH] shared_prefs: "any"
Accepts any version. Pin to a range like "^2.0.0".
────────────────────────────────────────────────────────────────
Summary
────────────────────────────────────────────────────────────────
Packages scanned 38
CVE / advisories 1
License violations 1
Health issues 2
Constraint warnings 1
Exit code is 1 when any CVE finding, license error, HIGH health issue, or HIGH constraint warning is present — so it blocks CI automatically.
# Scan and show everything
pubguardian scan
# Only care about HIGH and CRITICAL CVEs (good for blocking CI)
pubguardian scan --min-severity high
# Skip the pub.dev network calls — faster, works offline
pubguardian scan --skip-health
# Strict mode: flag LGPL and MPL-2.0 as well
pubguardian scan --license-policy strict
# Suppress a known false-positive
pubguardian scan --ignore GHSA-xxxx-yyyy-zzzz
# Output SARIF for GitHub Advanced Security
pubguardian scan --format sarif --output results.sarif
# Generate a CycloneDX SBOM
pubguardian scan --format cyclonedx --output sbom.cdx.json
# Output structured JSON for scripting
pubguardian scan --format jsonpubguardian scan [options]
-l, --lockfile pubspec.lock path (default: pubspec.lock)
-p, --pubspec pubspec.yaml path (default: pubspec.yaml)
-f, --format text | json | sarif | cyclonedx (default: text)
-o, --output Write output to a file instead of stdout
--min-severity critical | high | medium | low | unknown
--license-policy commercial | strict | permissiveOnly
--abandoned-days Days without a release before flagging (default: 365)
-i, --ignore Suppress a CVE/GHSA ID. Can be repeated.
--skip-health Skip pub.dev health checks
--skip-license Skip license analysis
--skip-constraints Skip constraint analysis
--exit-zero Always exit 0, even when findings exist
You pick how strict the license check should be:
| Policy | What gets flagged |
|---|---|
commercial (default) |
GPL-2/3, AGPL-3, SSPL — copyleft that affects commercial products |
strict |
Everything above plus LGPL, MPL-2.0, EUPL-1.2 |
permissiveOnly |
Anything that isn't MIT, Apache-2.0, BSD, ISC, or Unlicense |
# Use strict mode if you're shipping a closed-source product
pubguardian scan --license-policy strictsteps:
- uses: actions/checkout@v5
- uses: dart-lang/setup-dart@v1
- name: Install pubguardian
run: dart pub global activate pubguardian
- name: Block on HIGH/CRITICAL CVEs
run: pubguardian scan --min-severity highsteps:
- uses: actions/checkout@v5
- uses: dart-lang/setup-dart@v1
- name: Install pubguardian
run: dart pub global activate pubguardian
# Scan and upload findings to GitHub's Security tab
- name: Scan (SARIF)
run: pubguardian scan --format sarif --output results.sarif --exit-zero
- name: Upload to GitHub Advanced Security
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: results.sarif
# Generate a software bill of materials and keep it as an artifact
- name: Generate SBOM
run: pubguardian scan --format cyclonedx --output sbom.cdx.json --exit-zero
- uses: actions/upload-artifact@v5
with:
name: sbom
path: sbom.cdx.json
# Hard gate — fails the build if any HIGH or CRITICAL CVE is found
- name: CVE gate
run: pubguardian scan --min-severity high --skip-health --skip-license --skip-constraintssecurity-scan:
script:
- dart pub global activate pubguardian
- pubguardian scan --format sarif --output gl-sast-report.sarif --exit-zero
artifacts:
reports:
sast: gl-sast-report.sarifSkip the manual install — scan every push with a 3-line workflow:
steps:
- uses: sonofnos/pubguardian@v1
with:
args: scan --format sarif --output results.sarif --exit-zeroMake it a hard gate that fails the build on HIGH/CRITICAL CVEs:
steps:
- uses: sonofnos/pubguardian@v1
with:
args: scan --min-severity high --skip-health| Input | Default | Description |
|---|---|---|
args |
scan --exit-zero |
Arguments passed to the CLI. Omit --exit-zero to fail on findings. |
working-directory |
. |
Directory containing pubspec.yaml / pubspec.lock. |
version |
latest | Pin a specific version, e.g. 0.1.8. |
Block commits that introduce vulnerable dependencies (requires
dart pub global activate pubguardian once):
# .pre-commit-config.yaml
repos:
- repo: https://github.com/sonofnos/pubguardian
rev: v0.1.8
hooks:
- id: pubguardiandocker build -t pubguardian .
docker run --rm -v "$PWD":/app -w /app pubguardian scanCommon targets when developing the tool itself:
make install # dart pub global activate --source path .
make scan # text scan
make scan-sarif # results.sarif
make sbom # sbom.cdx.json
make build # native binary to build/pubguardian
make docker # build the docker imagepubguardian exposes its full pipeline if you want to integrate scanning into your own tooling:
import 'package:pubguardian/pubguardian.dart';
void main() async {
final runner = Runner();
final result = await runner.run(
const ScanConfig(
minSeverity: Severity.high,
licensePolicy: LicensePolicy.commercial,
),
onStatus: print,
);
runner.close();
final report = result.report;
print('${report.totalVulnerabilities} CVEs across ${report.totalPackages} packages');
for (final pkg in report.vulnerablePackages) {
for (final v in pkg.vulnerabilities) {
print('${pkg.name}: ${v.id} (${v.severity.name})');
}
}
}- Reads
pubspec.lock— gets the exact resolved version of every hosted dependency. - Sends them to
api.osv.dev/v1/querybatchin batches of 100. Retries on transient errors. - Hits
pub.dev/api/packages/{name}to check if each package is discontinued or stale. - Calls
api.deps.devto get the SPDX license identifier for each package (pub.dev doesn't expose this in its API). - Runs the licence, health, and constraint checks in-process.
- Prints or writes the result in whichever format you asked for.
Apache 2.0 — see LICENSE.