Developer & DevSecOps tooling — fast, single-purpose, CI- and agent-friendly. 100% offline, no account, no API key.
pip install cognis-shipcheck
shipcheck lint Dockerfile # best-practice + size + EOL/CVE advisories
shipcheck vulnmatch Dockerfile # match base-image packages vs 262k real OSV vulns — offlineshipcheck reads a Dockerfile, reports prioritized findings, and — with the
bundled offline OSV corpus — tells you which real CVEs affect the packages
your base image and RUN install steps actually pull in. It never touches the
network: the vulnerability database ships inside the wheel, so it runs the same
on a laptop or in an air-gapped enclave.
Real, reproducible output from the tool — runs offline:
$ shipcheck-emit --version
shipcheck 0.6.4$ shipcheck-emit --help
usage: shipcheck [-h] [--version] {lint,vulnmatch,db,feeds} ...
Dockerfile linter with image-size and CVE advisories.
positional arguments:
{lint,vulnmatch,db,feeds}
lint lint one or more Dockerfiles
vulnmatch match a Dockerfile's base-image + installed packages
against the bundled offline OSV vulnerability DB (262k
real vulns)
db query the bundled offline OSV vulnerability database
feeds list / refresh keyless intel feeds for edge & air-gap
use
options:
-h, --help show this help message and exit
--version show program's version number and exitBlocks above are real
shipcheckoutput — reproduce them from a clone.
Sample result format (illustrative values — run on your own data for real findings):
{
"findings": [
{
"id": "1234567890",
"title": "Example Finding 1",
"description": "This is an example finding.",
"type": "indicator",
"spec_version": "2.11.1"
},
{
"id": "2345678901",
"title": "Example Finding 2",
"description": "This is another example finding.",
"type": "attack-pattern",
"spec_version": "2.11.1"
}
]
}
- Why shipcheck? · Features · Quick start · Commands · Worked examples · Offline CVE DB · Edge / air-gap · Architecture · Polyglot ports · AI / MCP · How it compares · Integrations · Install anywhere · Scope & safety · Related · Contributing
shipcheck is single-purpose, scriptable, and self-hostable: point it at a
Dockerfile, get prioritized results in the format your workflow already speaks
(table · JSON), gate CI on the exit code, and let agents drive it over MCP. The
differentiator is the bundled, offline vulnerability database — 262,351 real
OSV records across PyPI / npm / Go / Maven / RubyGems / crates.io / NuGet — so
the vulnmatch subcommand resolves actual CVEs (yes, including
CVE-2021-44228 / Log4Shell) the moment you clone the repo, with zero network.
- Dockerfile linter — parses continuations + multi-stage builds, then runs a battery of rules across four families:
- Security hygiene — root user (
SC300),sudoinRUN(SC220),curl | shremote-exec (SC221), hard-coded secrets (SC230),ADDvsCOPY(SC240), SSH port exposure (SC260). - Cache / layer efficiency —
apt-get updatein its own layer (SC201), missing--no-install-recommends(SC202), uncleaned apt lists (SC203),pipwithout--no-cache-dir(SC210), earlyCOPY . .(SC250), RUN-layer bloat (SC310). - Image size — heavy base images with slimmer variants available (
SC110). - EOL / CVE advisories — unpinned /
:latesttags (SC101) and end-of-life base tags (SC120).
- Security hygiene — root user (
- Offline CVE enrichment (
vulnmatch) — inventories the packages a Dockerfile actually ships (base-image runtimes +pip/npm/gem/apt-get installargs) and matches them against the bundled 262k-record OSV DB. Fully offline; no fabricated data. - Direct DB queries (
db) —count,cve <ID>,package <name>,search <text>over the bundled corpus. - Edge data feeds (
feeds) — a catalog of 35 keyless intel feeds (CISA KEV, EPSS, OSV, NVD, GHSA, MITRE ATT&CK, abuse.ch, OSCAL 800-53 …) with a disk cache and air-gap snapshot transfer for refreshing the corpus on disconnected gear. - Outputs — human table (with severity colors) and machine
--format json; CI-friendly exit codes. - Polyglot ports — the linter surface in Python (reference), Go, Rust, and Node, each with a smoke test and CI.
- Runs everywhere — Linux / macOS / Windows · Docker · devcontainer · CI · MCP.
pip install cognis-shipcheck # or: pip install "git+https://github.com/cognis-digital/shipcheck.git"
shipcheck --version
shipcheck lint Dockerfile # lint one or more Dockerfiles
shipcheck lint Dockerfile --format json # machine-readable
shipcheck lint Dockerfile --fail-on high # CI gate (non-zero exit at >= high)
shipcheck vulnmatch Dockerfile # offline CVE match for image packages
shipcheck db count # -> 262351
shipcheck db cve CVE-2021-44228 # Log4Shell record, offlineExit codes: 0 clean / under threshold · 1 a finding met --fail-on
(default medium) or vulnmatch --fail-on-vulns matched · 2 file/usage error.
| Command | What it does |
|---|---|
shipcheck lint <Dockerfile>... |
Best-practice / size / EOL advisories. --format {table,json}, --fail-on {info,low,medium,high,critical}, --no-color. |
shipcheck vulnmatch <Dockerfile>... |
Inventory image packages and match against the bundled OSV DB. --format, --fail-on-vulns, --no-color. |
shipcheck db {count,cve,package,search} [arg] |
Query the bundled 262k-vuln OSV corpus. --limit, --ecosystem. |
shipcheck feeds list [--domain D] |
List the keyless edge/air-gap intel feeds (refresh via python -m shipcheck.datafeeds). |
shipcheck mcp |
Start an MCP stdio server exposing shipcheck_scan (needs the mcp extra). |
Lint a problematic Dockerfile
$ shipcheck lint Dockerfile
SHIPCHECK 0.6.4 Dockerfile
stages=1 instructions=4 findings=5
L1 CRITICAL SC120 node:12 - EOL: Node 12 is end-of-life; many unpatched CVEs
-> upgrade to a supported, patched tag
L1 INFO SC110 'node' is a large base image
-> consider node:<ver>-slim or node:<ver>-alpine
L2 HIGH SC201 'apt-get update' in its own layer causes stale-cache installs
-> chain 'apt-get update && apt-get install' in one RUN
L3 LOW SC210 pip install without --no-cache-dir leaves wheel cache
-> add --no-cache-dir
L4 HIGH SC300 container runs as root (no trailing USER directive)
-> add a non-root 'USER' before the final CMD/ENTRYPOINT
summary: high:2 low:1 info:1 critical:1 (max=critical)
Match base-image packages against real CVEs — offline
$ shipcheck vulnmatch Dockerfile
SHIPCHECK 0.6.4 Dockerfile (offline OSV match)
components=2 matches=12
org.apache.logging.log4j:log4j-core CVE-2021-44228 [critical] (base:openjdk)
Log4Shell: JNDI features used in configuration, log messages, and parameters do not...
org.apache.logging.log4j:log4j-core CVE-2021-45046 [critical] (base:openjdk)
Incomplete fix for CVE-2021-44228 in certain non-default configurations...
django CVE-2019-19844 [high] (pip-install)
Django password-reset account-takeover via crafted email...
12 real OSV record(s) matched · fully offline
JSON for dashboards / policy tooling
shipcheck lint Dockerfile --format json | jq '.reports[].findings[] | {code, severity, message}'
shipcheck vulnmatch Dockerfile --format json | jq '.reports[0].match_count'Query the bundled DB directly
shipcheck db count # 262351
shipcheck db package lodash --limit 5 # OSV records affecting lodash
shipcheck db search "deserialization" --limit 10shipcheck bundles cognis_vulndb.jsonl.gz — a consolidated, compact OSV
corpus of 262,351 real vulnerabilities with per-record metadata: id,
CVE / GHSA aliases, ecosystem, summary, severity, affected packages,
and published / modified dates. It loads lazily and indexes on first use;
pure standard library, no network, no key.
from shipcheck.vulndb_local import VulnDB
db = VulnDB()
db.count() # 262351
db.by_cve("CVE-2021-44228") # [ {id: GHSA-jfh8-c2jp-5v3q, ...} ]
db.by_package("lodash") # records affecting lodash
db.search("remote code execution", 20)vulnmatch maps a base image to the upstream package coordinates it ships
(e.g. openjdk → org.apache.logging.log4j:log4j-core, python →
pip / setuptools / wheel) and adds anything from pip / npm / gem /
apt-get install lines, then looks each up in the corpus. Ecosystem-aware so a
PyPI lodash query won't surface an unrelated npm package. No CVE is ever
fabricated — every match is a real OSV record from the bundle.
The bundle is the offline baseline. To keep it current on connected hosts and
sneakernet updates into a disconnected enclave, shipcheck.datafeeds ships a
catalog of 35 keyless feeds (CISA KEV, EPSS, OSV, NVD CVE 2.0, GitHub GHSA,
MITRE ATT&CK STIX, abuse.ch, NIST OSCAL 800-53, and more):
shipcheck feeds list --domain vuln # browse the catalog
python -m shipcheck.datafeeds update cisa-kev epss # fetch + disk-cache (online host)
python -m shipcheck.datafeeds get osv --offline # serve from cache, never touches network
python -m shipcheck.datafeeds bulk nvd-cve --max 200000 # paginate NVD/GHSA to disk
python -m shipcheck.datafeeds snapshot-export feeds.tar.gz # for transfer to the air gap
python -m shipcheck.datafeeds snapshot-import feeds.tar.gz # extract into the enclave's cacheThe cache location is $COGNIS_FEEDS_CACHE (default ~/.cache/cognis-feeds);
offline=True serves cache only. Standard library (urllib) only — no pip deps.
flowchart LR
DF[Dockerfile] --> P[parse<br/>continuations + multi-stage]
P --> R[rule engine<br/>SC101..SC310]
P --> INV[component inventory<br/>base + installs]
INV --> DB[(bundled OSV DB<br/>262k vulns, offline)]
R --> OUT[findings: table / JSON]
DB --> OUT
The linter command surface is mirrored in four languages under ports/,
each emitting the same SC### finding codes and a JSON report, each with a
smoke test wired into CI (.github/workflows/ports.yml):
| Language | Path | Run | Test |
|---|---|---|---|
| Python (reference) | shipcheck/ |
shipcheck lint Dockerfile |
pytest |
| Go | ports/go/ |
go run . Dockerfile |
go test ./... |
| Rust | ports/rust/ |
cargo run -- Dockerfile |
cargo test |
| Node | ports/javascript/ |
node index.js Dockerfile |
node index.test.js |
- MCP server —
shipcheck mcp(Claude Desktop, Cursor, Cognis.Studio). - JSON pipe — feed
shipcheck lint . --format jsoninto any agent or LLM. - LangChain · CrewAI · AutoGen · LlamaIndex — wrap the CLI/JSON as a tool.
- CI / scripts — exit codes for non-AI pipelines.
| Cognis shipcheck | hadolint | trivy | |
|---|---|---|---|
| Dockerfile best-practice lint | ✅ | ✅ | |
| Bundled offline CVE DB (262k) | ✅ | ❌ | needs DB download |
| Works fully air-gapped, no key | ✅ | ✅ | |
| Single command, zero config | ✅ | ||
| JSON for CI | ✅ | ✅ | ✅ |
| MCP-native (AI agents) | ✅ | ❌ | ❌ |
| Polyglot ports (Go/Rust/Node) | ✅ | ❌ | ❌ |
| Open license | ✅ COCL | OSS | OSS |
Built in the spirit of hadolint / trivy / dive, re-framed the Cognis way. Missing a credit? Open a PR.
Pipes into your stack: JSON for anything, an MCP server (shipcheck mcp)
for AI agents, and a shipcheck-emit forwarder
(STIX/TAXII · MISP · Sigma · Splunk · Elastic · Slack/Discord · webhook) via the
optional cognis-connect dependency. See docs/INTEGRATIONS.md
and INTEROP.md.
pip install "git+https://github.com/cognis-digital/shipcheck.git" # pip (works today)
pipx install "git+https://github.com/cognis-digital/shipcheck.git" # isolated CLI
uv tool install "git+https://github.com/cognis-digital/shipcheck.git" # uv
pip install cognis-shipcheck # PyPI (when published)
docker run --rm ghcr.io/cognis-digital/shipcheck:latest --help # Docker| Linux | macOS | Windows | Docker | Cloud |
|---|---|---|---|---|
scripts/setup-linux.sh |
scripts/setup-macos.sh |
scripts/setup-windows.ps1 |
docker run ghcr.io/cognis-digital/shipcheck |
DEPLOY.md |
shipcheck is defensive and passive by design. It reads Dockerfiles and a
bundled, local vulnerability database — it does not scan networks, probe
hosts, build images, run containers, or send any data anywhere. There is no
active-scanning mode. Vulnerability data is real OSV content only; nothing is
fabricated. Use it on artifacts you are authorized to inspect.
mcpforge— Scaffold, test, and publish MCP servers.promptlint— Lint, version, and test prompts as code.envdoctor— .env validator + config-drift checker.apidiff— Breaking-change detector for OpenAPI / GraphQL.codeglance— Repo onboarding map for humans and agents.flakefinder— Flaky-test detector from CI history.
Explore the suite → 🗂️ all tools · ⭐ awesome-cognis · 🔗 cognis-sources
PRs, new rules, and demo scenarios are welcome under the collaboration-pull model — see CONTRIBUTING.md and SECURITY.md.
shipcheck composes with the Cognis suite — JSON in/out and a shared
OpenAI-compatible /v1 backbone. See INTEROP.md for the suite
map, composition patterns, and reference stacks.
Source-available under the Cognis Open Collaboration License (COCL) v1.0 — free for personal, internal-evaluation, research, and educational use; commercial / production use requires a license (licensing@cognis.digital). See LICENSE.