SAST · SCA · secrets · IaC · containers, from one file, in your own CI
Know which findings to fix first.
Across the scanners you already run.
One file runs the ones your app needs, and then Draugr ranks everything they find against what the code cannot say: who can reach this service, what the business loses when it stops, and whether anybody is exploiting it today.
Open source · Runs in GitHub Actions, GitLab CI and Azure Pipelines
How that's possible, you tell it what the scanner can't know
# draugr.saga.yaml project: payments-api release: version: "1.4.0" components: - name: api exposure: public # strangers reach it criticality: critical # the business stops without it repositories: - url: https://github.com/acme/api.git
The same CVE is P1 on a public payments API and P3 on an internal batch job. draugr init writes the first draft.
Two more signals, before anything is ranked
↑ KEV · EPSS
On CISA's known-exploited list makes a finding critical; a high EPSS probability, its estimate of exploitation within 30 days, raises it one band.
↓ Reachability
On Go projects, govulncheck proves your code never calls the vulnerable function and the finding drops one band. It is never deleted.
That is the noise gone, and not by a filter that hides things but by an order.
Try it
curl -fsSL https://draugr.dev/install.sh | sh draugr scan . ⋯ gitleaks, semgrep and trivy are not installed, so iac, sast, sca and secrets would not run. Install them now with draugr tools install gitleaks semgrep trivy? [Y/n/never]
Run draugr scan . inside a git repository and findings come out most urgent first. On a terminal it asks before installing a scanner it is missing; answer Y and the scan runs.
Until draugr.saga.yaml says who can reach each component and what stops without it, the order is severity alone. draugr init writes the file, draugr classify records those two answers in it, and CI scans it once it is committed.
Commit the draugr.saga.yaml that draugr init writes, and a pull or merge request fails on a P1 finding it introduces.
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: draugr-dev/draugr@v0
with: { saga: draugr.saga.yaml, tools: true, fail-on-new: P1 }include:
- remote: 'https://raw.githubusercontent.com/draugr-dev/draugr/v0.166.3/gitlab-ci/draugr.yml'
stages: [test]# on Azure Repos, pull requests also need a build validation policy
steps:
- template: .azure/draugr.yml
parameters: { saga: draugr.saga.yaml }Your assistant calls Draugr through MCP, so the draugr binary must be on your PATH.
Claude Code
Guide →/plugin marketplace add draugr-dev/draugr
/plugin install draugr@draugrOther MCP clients
in the MCP Registry asdev.draugr/draugr{
"mcpServers": {
"draugr": { "command": "draugr", "args": ["mcp"] }
}
}What it checks, and what does the checking
Code, infrastructure code, dependencies, secrets and licenses; the images, clusters and cloud accounts it ships to; certificates, signatures and the running app, each checked by a scanner you already trust.
Every check, and what runs it →Already pay for something better? It goes in the same slot →SBOM and VEX, for the auditor →Findings where your team already looks →
And what comes out is a list of things to do
$ draugr scan . --view actions WHAT TO DO 50 actions clear 1154 findings Bump a dependency 12 actions clear 559 findings P1 Upgrade jquery 1.8.3 → 1.12.2 component storefront · control sca · 4 findings · web/package-lock.json:12 · NSWG-ECO-329 +3 ⋯ Change the code 14 actions clear 23 findings P1 Fix “Found user-controlled data used in a system call” Semgrep: dangerous-system-call · Bandit: B605 component api · control sast · 2 findings · app/app.py:16 ⋯ Change the infrastructure 21 actions clear 40 findings P1 Fix KSV-0118 “Default security context configured” control iac · 2 findings · deploy/pod.yaml:6 · KSV-0118 +1 ⋯
A row is an action, not a finding. Six vulnerabilities in one library are one upgrade, ranked by the worst thing it clears rather than by how many. Each kind of work has its own list, ordered by values the report records, so every position can be checked.
Two things that decide whether a team keeps it on
draugr diff
Gate a pull request on what it introduced, not the backlog it inherited. The only version of this a team can switch on with the backlog still there.
Wire it into CI →config.exclude
One way to excuse a finding, in the file that already describes your scope. It carries a reason and the date it lapses, and its git history records who accepted it.
Every field it takes →Those two meet: when an exclusion reaches its expiry the finding comes back on the next pull request, with nobody keeping a calendar.
Gating on what a change introduced →What a defensible exception carries →Every flag on the diff →
Where you already are
The answer, in your editor and your assistant.
In your editor
Underlines on the lines that caused them, in VS Code and JetBrains. Nothing to install.
In your coding assistant
draugr mcp gives it your committed descriptor, so it answers with the same verdict as CI instead of a scope it chose for itself.
In the MCP Registry as dev.draugr/draugr, and as a Claude Code plugin.
Make the fast path the secure path.
Open source, released, and it runs where you run it. Draugr Server keeps the history across an organization and is in early access.