Skip to main content

valvur

A fully offline security scanner for AI-generated code. Your source never leaves your machine — and you can prove it.

Status: 0.2.0 — published and installable; v1.0.0 follows the usability gate. pip install valvur · ghcr.io/maverickhq/valvur


Why this exists

Every serious code-security scanner sends your code — or metadata about it — to someone else's servers. For regulated industries and data-residency jurisdictions that is not a preference to negotiate; it ends the procurement conversation. valvur runs entirely on your machine, with networking switched off and your source mounted read-only.

At the same time, AI now writes a fast-growing share of production code, and it fails in ways classic scanners were never built to catch: hallucinated dependencies that attackers pre-register, poisoned agent instruction files, hidden Unicode directives.

Offline scanning, built for how AI-generated code actually breaks.

The three claims

This is the introduction. docs/EVALUATING.md is the audit — the measured first run, the verification commands, the three statuses, and a plain list of what valvur does not claim. Read that one sceptically.

1. It cannot exfiltrate your code — and you can verify it

No account, no API key, no telemetry: nothing to opt out of. On the default offline profile the scanners run in containers with --network=none, and the host process that launches them opens no socket either. Both halves are checked by one command:

python3 scripts/verify-offline.py /path/to/your/repo

On Linux the OS can deny the whole process tree the network, no privileges needed: unshare -rn valvur scan --profile offline. Every run records in run.json exactly what left the machine — on offline, the word nothing.

2. Security checks built for AI-generated code

  • Hallucinated dependencies (slopsquatting). LLMs invent package names; attackers register them. No advisory database can catch it — the package is new, not known-bad. valvur checks that every declared dependency exists, offline, against a local index of every name on PyPI, npm, RubyGems, Packagist and crates.io (6.3 million names, exact, published daily and signed). On full it also asks how old each one is, and whether it is one edit from something popular.
  • Agent-config auditing. CLAUDE.md, AGENTS.md, .cursorrules, .mcp.json, skills and prompt files — scanned for injected directives, hidden Unicode (zero-width, bidi, tag characters), unpinned @main MCP refs, blanket autoApprove and permission-bypass flags.
  • A small set of Opengrep rules for model output reaching eval, exec, a shell, SQL or innerHTML, and for unpinned actions and mutable git refs.

What is covered, and what is not, is stated on every scan rather than left to infer:

ecosystem exists? known CVEs?
Python, npm, Ruby, PHP, Rust offline, from the index needs requirements*.txt, uv.lock, poetry.lock / a lockfile
JVM, Go full only — no offline index exists for either registry pom.xml, go.mod on their own

A manifest with no lockfile beside it, or a manifest nothing here reads (a lone Pipfile, say), is a coverage note: the run reads inconclusive rather than clean, and names why. That reporting is the part we consider non-optional.

3. Ten things that matter, not four hundred findings

Findings are ranked by whether attackers are actually exploiting them — CISA KEV (including the ransomware-campaign flag) and FIRST EPSS — not by CVSS theatre. Development-only dependencies are demoted; transitive vulnerabilities come with the path and the direct package to bump.

Finding CVSS EPSS KEV Severity-sorted Ranked here
CVE in a dev-only test library 9.8 CRITICAL 0.04% No #1 #40
CVE in your production web framework 6.5 MEDIUM 92% Yes #40 #1

For AI coding agents — the primary way in

Add valvur to your agent's MCP configuration:

{ "mcpServers": { "valvur": { "command": "uvx", "args": ["--from", "valvur", "valvur-mcp"] } } }

Then ask it to scan. The server is stdio only — no listener, no port — and every tool it exposes is read-only: valvur can never change your code.

Add this to your project's CLAUDE.md or AGENTS.md, so the agent uses what it has:

## Security scanning
This project uses valvur. Scan with the `valvur` MCP tools if you have them:
call `scan`, then `scan_status` until it reports DONE. Otherwise run
`valvur scan`. Results appear in `.security-scan/`: read SUMMARY.md, then
REMEDIATION.md. Never commit `.security-scan/`. Never add suppressions without
explicit human approval. Propose fixes for approval — do not apply them and
rescan autonomously.

For developers

pip install valvur          # or: uv tool install valvur
valvur update               # the image, the vulnerability database and the name index, once
valvur scan                 # offline by default; --profile full adds the networked checks

The first valvur update pulls the image (about 240MB), the vulnerability database (118MB) and the name index (34MB, one signed artifact, built daily) — a minute or two. Later updates take seconds; run valvur update --if-stale from a hook or cron, it costs one file read when current. A scan that finds the image missing pulls it and says so — over MCP, scan_status reads "pulling ghcr.io/…" with the size — rather than sitting silent. If the published index cannot be reached, the five registries are walked directly instead, which takes about seven minutes once.

Results land in .security-scan/:

.security-scan/
├── SUMMARY.md          ← start here. Bounded, leads with anything that failed
├── REMEDIATION.md      ← ranked proposal, with dependency paths and upgrade targets
├── findings.json       ← complete, normalised, schema-versioned
├── results.sarif       ← SARIF 2.1.0 for your IDE
├── sbom.cdx.json       ← CycloneDX SBOM
├── run.json            ← what ran, which versions, what was skipped and why
└── raw/                ← untouched per-tool output, so you can verify us

The folder ignores itself, so results are never committed. Secrets are redacted in every artifact, raw/ included. You decide which fixes to apply and when to rescan — there is no autonomous loop. Suppressions (with mandatory expiry dates) and [scan] exclude paths live in a committed .security-scan.toml, and every exclusion is reported with what it cost.

What actually does the scanning

valvur builds no detection engine. Six open source scanners do that and deserve the credit; valvur adds orchestration, one findings model, exploit-aware ranking, and the checks under claim 2.

Tool Licence Does
Trivy Apache-2.0 Dependency vulnerabilities
Gitleaks MIT Secrets, including git history
OSV-Scanner Apache-2.0 Dependencies against OSV.dev (full)
Opengrep LGPL-2.1 Static analysis
Checkov Apache-2.0 Infrastructure misconfiguration
Syft Apache-2.0 SBOM, and the dependency licences read from it

Exploit intelligence comes from CISA KEV and FIRST EPSS — public primary sources, auditable and mirrorable. No proprietary database; nothing to lock you in.

What it deliberately does not do

  • No reachability analysis. We do not prove a vulnerable function is called.
  • No autonomous fixing. You choose the fixes.
  • No penetration testing. No DAST, no exploitation, no scanning of deployed systems.
  • No code-quality analysis. Security only.
  • We will not out-detect commercial SAST. We win on trust, breadth in one artifact, and prioritisation — not on engine depth.

Platforms

macOS, Linux — Docker or Podman Supported, tested on every commit against both runtimes
linux/amd64 and linux/arm64 Both, from 0.2.0. 0.1.0rc1 was published arm64 only — a defect, not a policy
Windows via WSL2 Supported — inside WSL valvur is running on Linux
Native Windows Not claimed. Untested, and valvur says so at startup
SELinux-enforcing hosts (RHEL, Fedora) Supported, with one deliberate friction: valvur will not relabel your source tree unless you set VALVUR_SELINUX_RELABEL=1. Details in EVALUATING.md

Air-gapped? The database, the name index and KEV all live outside the image and each has a mirror setting, measured end to end. See docs/AIR-GAPPED.md.

Contributing, and reporting problems

A finding you disagree with — especially one valvur missed — is a bug worth reporting. CONTRIBUTING.md has the setup and the short list of things refused on principle; SECURITY.md is for suspected vulnerabilities, which for a security tool include a false clean result; CHANGELOG.md is what changed.

Licence

Apache-2.0 — see LICENSE; chosen over MIT for the explicit patent grant. Bundled scanners keep their own licences, listed above. valvur adds no GPL or AGPL component; the Alpine base carries GPL userland as every Linux container does, and the published SBOM discloses all of it (ADR-0005).

Release files for valvur 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for valvur 0.2.0
File Size Uploaded
valvur-0.2.0.tar.gz 747.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for valvur 0.2.0
File Interpreter ABI Platform
valvur-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 935.2 kB

Release files / valvur-0.2.0.tar.gz

Download URL valvur-0.2.0.tar.gz
Size 747.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8fdb047a2934de89a3022bd7eb339fcc9304a6c028e7e039cf6a2ce54e10f4a3
BLAKE2b-256 checksum
How to use checksums
fdb29eb10e2ca9208e686695fc6f5c44fbca992693e21ebe07fdbd2c656867e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release files / valvur-0.2.0-py3-none-any.whl

Download URL valvur-0.2.0-py3-none-any.whl
Size 187.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c6e89cc3e0433926337d8c6845f64ed599cd24e5b2fffcec5a6f3348c4dc3796
BLAKE2b-256 checksum
How to use checksums
ff862872543594af6b81ac59ac60ffa4d89f2d35c44c6dc594ffa584f2758491
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page