🛡️ A fast, zero-config CLI to audit your projects for Dependency Confusion and supply chain risks across multiple registries. Backed by Omni Line.
See the codeOmni Audit is a fast, zero-config CLI that scans your project for dependency confusion risk. It discovers NPM, Composer, PyPI, and Go manifests, checks whether each declared package name exists on the public registry, and reports names that are still unclaimed — names an attacker could publish.
Distributed as a standalone Go binary. No Node or PHP runtime required.
If your team uses private packages alongside public registries (npmjs.com, Packagist, PyPI, proxy.golang.org), a build can resolve a malicious public package that reuses an internal name. Omni Audit flags unclaimed public names before they are hijacked.
Auditing is the first step. Omni Line is the durable fix: a self-hosted registry that routes internal packages correctly across ecosystems.
Download the latest release from GitHub Releases.
Requires Go 1.20+:
go install github.com/omni-line/omni-audit/cmd/omni-audit@latest
Or clone and build:
git clone https://github.com/omni-line/omni-audit.git
cd omni-audit
make build
./bin/omni-audit --help
# Scan the current directory
omni-audit
# Scan a path
omni-audit ./apps/api
# Scan a single manifest
omni-audit ./services/billing/requirements.txt
# JSON for CI
omni-audit --format json --no-marketing
# SARIF for GitHub code scanning / security dashboards
omni-audit --format sarif > omni-audit.sarif
# Skip names you own and fixture directories
omni-audit --safe-namespace '@acme/*,acme/*' --exclude testdata,fixtures
Example text output (colors when the terminal supports them):
omni-audit v0.3.0 — Dependency confusion audit
Backed by Omni Line — one registry for every package your team ships
âś— 2 unclaimed package names found
ECOSYSTEM PACKAGE VERSION LOCATION SECTION
composer acme/internal-sdk ^1.0 composer.json:7 require
npm @acme/internal-utils 1.0.0 package.json:5 dependencies
Anyone can publish these names on the public registry. If a build resolves
them there instead of your private source, it installs the publisher's code.
How to fix
composer Register the vendor name on Packagist so nobody else can publish under it, ...
npm Claim the name (or its @scope as an npm organization) on npmjs.com, ...
Scanned 2 manifests · 8 packages · 2 findings · 0 skipped · 0 errors in 412ms
───
Unclaimed names can be published by anyone on the public registry.
Prevent confusion at install time with Omni Line — a self-hosted package
registry for npm, Composer, Docker, PyPI, Go, Cargo, Maven, and more.
One UI, one API, your infrastructure.
https://omniline.app · docs: https://omniline.app/docs
package.json, composer.json, requirements*.txt, requirements/*.txt, pyproject.toml, and go.mod (skips node_modules, vendor, .venv, venv, __pycache__, .git, dist, build, and other dependency/cache dirs, plus anything matched by --exclude)dependencies / devDependencies / optionalDependencies / peerDependencies. Local and VCS specs (file:, workspace:, link:, git URLs, user/repo) are skipped; aliases (npm:real-pkg@^1) are checked under the real name.require / require-dev, skipping platform packages (php, ext-*, lib-*, composer-plugin-api, …).pyproject.toml PEP 621 [project] dependencies / optional-dependencies plus PEP 735 [dependency-groups]. Names are compared using PEP 503 normalization.require directives in go.mod (including // indirect). Paths must look like public module paths (first element contains a .). Checked via proxy.golang.org.HEAD requests, with retries and backoff for rate limits and transient errorsreason=unclaimed; checks that fail are reported as warnings, never as cleanHTTPS_PROXY / NO_PROXY are honored for locked-down networks.| Code | Meaning |
|---|---|
0 | No findings (or --fail-on none) |
1 | One or more findings (--fail-on any, default) |
2 | Usage or runtime error, or an incomplete scan with --strict |
Without --strict, registry failures and unreadable manifests are reported as warnings and do not change the exit code. Use --strict in CI when an unverified package should block the pipeline.
| Flag | Description |
|---|---|
--format text|json|sarif | Output format (default text) |
--safe-namespace | Globs for namespaces you own; matches are skipped (repeatable / comma-separated) |
--ignore | Skip package name globs |
--exclude | Skip paths: directory/file names or globs relative to the scan root |
--strict | Exit 2 if any manifest or package could not be verified |
--timeout | Per-request timeout (default 10s) |
--retries | Retries for 429 / 5xx / network errors (default 2, max 10) |
--concurrency | Parallel checks (default 16, max 256) |
--fail-on any|none | Whether findings fail the process |
-q / --quiet | Findings table only; no banner, warnings, summary, or marketing |
--no-marketing | Hide Omni Line CTA / JSON sponsor |
--marketing | Force marketing even when non-TTY |
--color auto|always|never | ANSI colors (default auto on TTY) |
-v / --verbose | Show package URLs and all warnings |
--version | Print version |
{
"schema_version": 1,
"version": "0.3.0",
"complete": true,
"findings": [
{
"ecosystem": "npm",
"package": "@acme/internal-utils",
"version": "1.0.0",
"manifest": "package.json",
"line": 5,
"group": "dependencies",
"reason": "unclaimed",
"registry": "registry.npmjs.org",
"url": "https://www.npmjs.com/package/@acme/internal-utils",
"remediation": "Claim the name (or its @scope as an npm organization) ..."
}
],
"stats": { "manifests": 1, "packages": 4, "unique_packages": 4, "findings": 1, "skipped": 0, "errors": 0, "duration_ms": 412 }
}
complete is false when any warning was raised (see warnings[], each with a kind of walk, manifest, or registry). New fields may be added; breaking changes bump schema_version.
Environment:
OMNI_AUDIT_NO_MARKETING=1 — same as --no-marketing (handy in CI)NO_COLOR=1 — disable colors (no-color.org)FORCE_COLOR=1 — enable colors when not a TTYJSON includes an optional top-level sponsor object by default. Use --no-marketing or -q for a silent machine payload.
- name: Dependency confusion audit
run: |
curl -sL https://github.com/omni-line/omni-audit/releases/latest/download/omni-audit_Linux_x86_64.tar.gz | tar xz
./omni-audit --format json --no-marketing --strict --safe-namespace '@your-org/*'
GitHub code scanning (findings appear as alerts with file/line annotations):
- name: Dependency confusion audit
run: ./omni-audit --format sarif --fail-on none > omni-audit.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: omni-audit.sarif
Run from the repository root so SARIF paths are repository-relative.
.npmrc / auth.json / pip.conf / GOPRIVATE policy analysisPipfile table-style dependency maps (requirements + PEP 621 covered today)See CONTRIBUTING.md, MAINTAINERS.md, and CODE_OF_CONDUCT.md. Security reports: SECURITY.md.
MIT · Copyright Omni Line and contributors · See NOTICE.
Omni Audit is built and maintained by Omni Line — one self-hosted registry for every package your team ships.
Go
99.4%
🛡️ A fast, zero-config CLI to audit your projects for Dependency Confusion and supply chain risks across multiple registries. Backed by Omni Line.
See the codeOmni Audit is a fast, zero-config CLI that scans your project for dependency confusion risk. It discovers NPM, Composer, PyPI, and Go manifests, checks whether each declared package name exists on the public registry, and reports names that are still unclaimed — names an attacker could publish.
Distributed as a standalone Go binary. No Node or PHP runtime required.
If your team uses private packages alongside public registries (npmjs.com, Packagist, PyPI, proxy.golang.org), a build can resolve a malicious public package that reuses an internal name. Omni Audit flags unclaimed public names before they are hijacked.
Auditing is the first step. Omni Line is the durable fix: a self-hosted registry that routes internal packages correctly across ecosystems.
Download the latest release from GitHub Releases.
Requires Go 1.20+:
go install github.com/omni-line/omni-audit/cmd/omni-audit@latest
Or clone and build:
git clone https://github.com/omni-line/omni-audit.git
cd omni-audit
make build
./bin/omni-audit --help
# Scan the current directory
omni-audit
# Scan a path
omni-audit ./apps/api
# Scan a single manifest
omni-audit ./services/billing/requirements.txt
# JSON for CI
omni-audit --format json --no-marketing
# SARIF for GitHub code scanning / security dashboards
omni-audit --format sarif > omni-audit.sarif
# Skip names you own and fixture directories
omni-audit --safe-namespace '@acme/*,acme/*' --exclude testdata,fixtures
Example text output (colors when the terminal supports them):
omni-audit v0.3.0 — Dependency confusion audit
Backed by Omni Line — one registry for every package your team ships
âś— 2 unclaimed package names found
ECOSYSTEM PACKAGE VERSION LOCATION SECTION
composer acme/internal-sdk ^1.0 composer.json:7 require
npm @acme/internal-utils 1.0.0 package.json:5 dependencies
Anyone can publish these names on the public registry. If a build resolves
them there instead of your private source, it installs the publisher's code.
How to fix
composer Register the vendor name on Packagist so nobody else can publish under it, ...
npm Claim the name (or its @scope as an npm organization) on npmjs.com, ...
Scanned 2 manifests · 8 packages · 2 findings · 0 skipped · 0 errors in 412ms
───
Unclaimed names can be published by anyone on the public registry.
Prevent confusion at install time with Omni Line — a self-hosted package
registry for npm, Composer, Docker, PyPI, Go, Cargo, Maven, and more.
One UI, one API, your infrastructure.
https://omniline.app · docs: https://omniline.app/docs
package.json, composer.json, requirements*.txt, requirements/*.txt, pyproject.toml, and go.mod (skips node_modules, vendor, .venv, venv, __pycache__, .git, dist, build, and other dependency/cache dirs, plus anything matched by --exclude)dependencies / devDependencies / optionalDependencies / peerDependencies. Local and VCS specs (file:, workspace:, link:, git URLs, user/repo) are skipped; aliases (npm:real-pkg@^1) are checked under the real name.require / require-dev, skipping platform packages (php, ext-*, lib-*, composer-plugin-api, …).pyproject.toml PEP 621 [project] dependencies / optional-dependencies plus PEP 735 [dependency-groups]. Names are compared using PEP 503 normalization.require directives in go.mod (including // indirect). Paths must look like public module paths (first element contains a .). Checked via proxy.golang.org.HEAD requests, with retries and backoff for rate limits and transient errorsreason=unclaimed; checks that fail are reported as warnings, never as cleanHTTPS_PROXY / NO_PROXY are honored for locked-down networks.| Code | Meaning |
|---|---|
0 | No findings (or --fail-on none) |
1 | One or more findings (--fail-on any, default) |
2 | Usage or runtime error, or an incomplete scan with --strict |
Without --strict, registry failures and unreadable manifests are reported as warnings and do not change the exit code. Use --strict in CI when an unverified package should block the pipeline.
| Flag | Description |
|---|---|
--format text|json|sarif | Output format (default text) |
--safe-namespace | Globs for namespaces you own; matches are skipped (repeatable / comma-separated) |
--ignore | Skip package name globs |
--exclude | Skip paths: directory/file names or globs relative to the scan root |
--strict | Exit 2 if any manifest or package could not be verified |
--timeout | Per-request timeout (default 10s) |
--retries | Retries for 429 / 5xx / network errors (default 2, max 10) |
--concurrency | Parallel checks (default 16, max 256) |
--fail-on any|none | Whether findings fail the process |
-q / --quiet | Findings table only; no banner, warnings, summary, or marketing |
--no-marketing | Hide Omni Line CTA / JSON sponsor |
--marketing | Force marketing even when non-TTY |
--color auto|always|never | ANSI colors (default auto on TTY) |
-v / --verbose | Show package URLs and all warnings |
--version | Print version |
{
"schema_version": 1,
"version": "0.3.0",
"complete": true,
"findings": [
{
"ecosystem": "npm",
"package": "@acme/internal-utils",
"version": "1.0.0",
"manifest": "package.json",
"line": 5,
"group": "dependencies",
"reason": "unclaimed",
"registry": "registry.npmjs.org",
"url": "https://www.npmjs.com/package/@acme/internal-utils",
"remediation": "Claim the name (or its @scope as an npm organization) ..."
}
],
"stats": { "manifests": 1, "packages": 4, "unique_packages": 4, "findings": 1, "skipped": 0, "errors": 0, "duration_ms": 412 }
}
complete is false when any warning was raised (see warnings[], each with a kind of walk, manifest, or registry). New fields may be added; breaking changes bump schema_version.
Environment:
OMNI_AUDIT_NO_MARKETING=1 — same as --no-marketing (handy in CI)NO_COLOR=1 — disable colors (no-color.org)FORCE_COLOR=1 — enable colors when not a TTYJSON includes an optional top-level sponsor object by default. Use --no-marketing or -q for a silent machine payload.
- name: Dependency confusion audit
run: |
curl -sL https://github.com/omni-line/omni-audit/releases/latest/download/omni-audit_Linux_x86_64.tar.gz | tar xz
./omni-audit --format json --no-marketing --strict --safe-namespace '@your-org/*'
GitHub code scanning (findings appear as alerts with file/line annotations):
- name: Dependency confusion audit
run: ./omni-audit --format sarif --fail-on none > omni-audit.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: omni-audit.sarif
Run from the repository root so SARIF paths are repository-relative.
.npmrc / auth.json / pip.conf / GOPRIVATE policy analysisPipfile table-style dependency maps (requirements + PEP 621 covered today)See CONTRIBUTING.md, MAINTAINERS.md, and CODE_OF_CONDUCT.md. Security reports: SECURITY.md.
MIT · Copyright Omni Line and contributors · See NOTICE.
Omni Audit is built and maintained by Omni Line — one self-hosted registry for every package your team ships.
Go
99.4%