← All articles

Scan any repo for vulnerabilities with zero config

July 17, 2026 · Wilson Santos · updated November 1, 2026
On this page

The fastest way to lose a developer is to make them read documentation before they see a result. Security tools are the worst offenders. Install the CLI, then write a config file, then figure out which scanners to enable, then install those scanners, and then, maybe, a finding. By step three most people have closed the tab.

So we cut the steps. Draugr scans a repository with no descriptor at all:

draugr scan .

Point it at a repo (or omit the argument for the current one) and Draugr runs the repository-level controls, being dependency vulnerabilities (SCA), leaked secrets, static analysis (SAST), and IaC misconfiguration, adds the scanners the files in the tree call for, and prints a prioritized verdict. No YAML, no flags, and nothing to write between git clone and "here's what to fix first."

Here it is against draugr-demo, a deliberately broken Flask app, with no descriptor and no flags:

DRAUGR  FAIL  draugr-demo  4.389s

 33 P1 27 P2 19 P3 0 P4
 No component declares exposure or criticality, so every one is read as public and critical.
 These bands rank severity alone. `draugr classify` makes them describe this application.

CONTROLS
  iac      FAIL   4 P1 5 P2 12 P3
  sast     FAIL   13 P1 5 P2 5 P3
  sca      FAIL   15 P1 17 P2 2 P3
  secrets  FAIL   1 P1

MEASURED AGAINST
  sca      govulncheck v1.8.0;db@2026-10-27 21:16:18 · database: local copy, fetched 2026-11-01

FOUND  read from the tree · `draugr init` writes them to draugr.saga.yaml
  python             app/requirements.txt                                       sca
  go                 checkout/go.mod                                            sca · gosec · govulncheck
  npm                web/package-lock.json · web/package.json                   sca
  copied JavaScript  app/static/js/jquery.min.js · web/static/js/jquery.min.js  retirejs
  Kubernetes         deploy/pod.yaml                                            iac
  Dockerfile         app/Dockerfile                                             iac · images off

SIGNALS
  floor         nothing raised
  reachability  govulncheck · 2 reachable, 3 unreachable

ACCEPTED
  scanner exclusions  1 finding suppressed

FIX FIRST  top 10 of 79, by priority
  P1  critical  CVE-2019-20477 · command execution through python/object/apply constructor in…
      scanner trivy · PyYAML 5.1 → 5.2
      app/requirements.txt:4

  P1  critical  CVE-2020-14343 · incomplete fix for CVE-2020-1747
      scanner trivy · PyYAML 5.1 → 5.4
      app/requirements.txt:4

  P1  critical  CVE-2020-1747 · arbitrary command execution through python/object/new when…
      scanner trivy · PyYAML 5.1 → 5.3.1
      app/requirements.txt:4

  …

… and 69 findings not listed.

Why zero-config, not zero-value

Plenty of tools offer a "quick start" that scans nothing useful. The point here isn't to skip the work. It is to defer the configuration until you've seen it's worth it. The zero-config run is real, using the same engine, the same scanners and the same P1–P4 prioritization Draugr uses in CI. You just haven't had to describe your app yet.

When you do want control, whether that is picking specific controls, adding container images or endpoints, or classifying components so prioritization reflects real exposure, you graduate to a descriptor. And you don't write it from scratch:

draugr init

init reads the same files the scan listed under FOUND and writes a draugr.saga.yaml from them, with a comment beside each line naming the files behind it. A Go module turns on gosec and ranks a Go finding down when no code calls the vulnerable function. Copied JavaScript such as jquery-1.8.3.min.js turns on retire.js, and a Dockerfile adds a commented image stub. A dependency file no scanner can read, like a package.json with no lockfile, is listed so you know its packages go unchecked. You start from a commented file that describes your repository and edit down, rather than from a blank page and a schema reference.

And if the thing you are describing is already running, draugr survey reads it rather than guessing:

draugr survey k8s images -o draugr.saga.yaml

That writes a component per namespace, each carrying the images running in it with the digest they are running, rather than the tag they were deployed under. It proposes each component's exposure from the namespace's own topology, an Ingress or a NetworkPolicy, and says in a comment beside the value what it read that from. Those are guesses to confirm with draugr classify, which is why they arrive announced rather than quietly. A GitHub organization works the same way. A team that owns one namespace can write a fragment instead, for a descriptor somebody else maintains.

The path we're optimizing for

There's a natural progression, and each step should take seconds:

  1. draugr scan . to see a real, prioritized verdict with zero setup.
  2. draugr init to turn that into a descriptor you own.
  3. The GitHub Action for the same scan in CI, findings in the Security tab, gated on new issues in a PR.

The tool that respects your time at step one is the tool you'll reach for at step three. That's the whole idea of describing your app rather than your scanners, and don't even make you do that until you've seen the value.

Try it. Two lines, and the installer verifies the release signature before it installs anything:

curl -fsSL https://draugr.dev/install.sh | sh
draugr scan .

It's Apache-2.0 and it runs entirely on your machine.