VyQL Docs Company Star on GitHub

Open source · Apache-2.0

It shows the whole path, and what is missing.

VyQL follows untrusted input through your code, to the place where it becomes dangerous. Then it names the controls that should have stopped it there. If a path exists, you see every step of it. If a control already covers the path, VyQL reports nothing.

$ curl -fsSL https://dl.vyprsec.ai/vyql/install.sh | sh

macOS and Linux, amd64 and arm64. It checks the checksum and installs to ~/.local/bin. There is no signup and no API key, and nothing leaves your machine.

Other Ways to Install

Homebrewbrew install vyprai/tap/vyql
Containerdocker run --rm -v "$PWD:/work" ghcr.io/vyprai/vyql scan .
Gogo install github.com/vyprai/vyql/cmd/vyql@latest && vyql update -yes
GitHub Actionsvyql-security-scan
Claude Code/plugin marketplace add vyprai/claude-plugins

Homebrew, Docker, release archives, and the install script ship the free definitions with the engine. go install is the engine only; follow it with vyql update -yes, or run an interactive scan and accept the download prompt.

Quickstart

From the Terminal

These commands cover almost everything you need:

vyql scan .                      # everything in this tree
vyql explain .                   # why each finding fired
vyql scan -fail-on none .        # report without failing the shell
vyql scan -exclude node_modules -exclude '**/*_templ.go' .   # skip these
vyql scan -baseline .vyql-baseline.json .   # only what is new

Reviewing one change is a different question than reviewing a whole repository. For that, scan both sides and compare them. The comparison uses a fingerprint, so if you move a function, it does not appear as a new finding:

git worktree add -q /tmp/base $(git merge-base HEAD origin/main)
vyql scan -format json /tmp/base > before.json
vyql scan -format json .        > after.json
vyql diff before.json after.json

Through an Agent

VyQL also ships as an agent skill. Then you can ask a question instead of remembering the flags. In Claude Code:

/plugin marketplace add vyprai/claude-plugins
/plugin install vyql@vypr

After that it works as a conversation. Every answer keeps the context of the previous one, so you do not need to repeat which finding you mean:

you  audit this repo for security problems

     Scanning the whole tree. vendor/, node_modules/ and testdata/ are
     skipped already. On top of those I would skip:

       **/*_templ.go    generated templates, one huge function each
       examples/        sample code, not shipped

     Anything else to leave out, or shall I go?

you  go

     scanned python:14 javascript:3, 2 files unread (.kt)
     7 findings. 2 critical, 3 high, 2 medium.
     1. VYQL-INJ-002  critical  api/users.py:88  request body reaches a shell
     2. VYQL-PATH-001 high      api/files.py:23  query param reaches open()
     ...

you  verify the high ones

     4 families: INJ (2), PATH (3), CRY (1), CFG (1). Verifying all four,
     one agent each. Nothing deferred.

     INJ   1 real, 1 false positive
     PATH  3 false positives, all through the same startswith() guard
     CRY   1 real
     CFG   1 unresolved, needs to know whether debug mode ships

     The three PATH findings share a cause. That guard is a containment
     check VyQL does not model, so it is a binding gap, not three bugs.

you  what about the INJ one

     Real. api/users.py:88 is a request handler and the path carries the
     value with no escaping. Fix is core.ShellEscape: subprocess with a
     list rather than shell=True.

you  prove it

     Booting from a clean worktree at the scanned commit.
     POST /users/import with a payload of "; id" returns uid=0(root).
     Torn down.

you  fix it then

     One file, api/users.py, introducing subprocess with an argument list.
     Shall I?

A reproduction runs only against your own machine, and the skill asks you first before it runs one. Writing the reproduction is the result. Whether to run it is your decision.

It runs the commands, and it tells you what was read before it tells you what it found. It asks first before it installs anything, before it scans, and before it writes a reproduction. It asks about scope because scope decides what the scan cannot find — a directory skipped there is one the report calls clean without having read it. And it never shortens a list of findings without saying so. The skill itself is a plain SKILL.md file in an open format, so any agent that can read it can follow the same steps. Claude Code is only the one that has an installer for it.

Either Way, the Same Shape

Agree what you are looking at, scan it, read the coverage line, then read the list. Verify the findings that matter to you, and reproduce one if you need proof. You can stop at any point where you already have your answer. For most scans, the list is enough.

What a Finding Looks Like

An Express app that takes a filename from the query string and passes it to the filesystem:

// app.js
const express = require("express");
const fs = require("fs");
const app = express();

app.get("/download", (req, res) => {
  const name = req.query.name;
  res.send(fs.readFileSync("/var/data/" + name));
});

There is no config file, and you do not choose which rules to run:

$ vyql scan .
analysis profile: HTTP API server (api)

2 finding(s):

[P3] [HIGH] VYQL-PATH-001  (conf=high, fp=c61843fd71a2284b)
  source: code.HttpInput @ app.js:6
  sink: code.FilePathAccess @ app.js:7
  taint path: app.jsAttr#80 -> app.jsFormat#81 -> app.jsArg#83
  unless path coveredBy core.PathCanonicalization: not satisfied, no neutralizing
    control dominates the path; none found anywhere on flows
  unless endpoint coveredBy core.PathAccessCheck: not satisfied, no guard on sink

Look at the last two lines. Most scanners tell you that something is wrong, and the rest of the work stays with you. VyQL names the control that would have fixed it. And if you already have that control in your code, VyQL tells you why it did not apply here.

What You Get

Knowledge as Data

A small Go engine, plus 12,400 .vyql files that you can open and edit. To add a framework you usually write a binding. You do not patch Go.

One Graph, 22 Languages

Java, Python and JavaScript are the most complete ones. The other languages have less coverage, and every scan tells you what you really got.

Built for CI

scan exits 3 when it finds anything high or critical, and 1 only when it could not run. SARIF and JSON output. Baseline files, for a codebase that already has findings.

It Tells You What It Did Not Read

Files that no frontend could read are reported, also when you do not ask for it. Without that line, a clean result over code that nobody read looks the same as a result that is really clean.

Downloads

847 release downloads

2026-08-05 2026-09-20 1,000

Counted from GitHub release assets since 2026-08-05. Continuous integration and mirrors are included. go install and container pulls are not counted at all.