GapScan Developer Docs
Early alpha · engine licensed Apache-2.0

GapScan developer docs

GapScan measures software against the standard it answers to and reports every unmet control as a gap, with evidence. The first standard is application security: OWASP ASVS 5.0, Top 10:2025, API Top 10, MASVS and the Top 10 for LLM apps.

These docs cover the open-source engine you can run today on your own machine. The cloud service is in development; the parts that depend on it are marked.

GapScan never runs your code. Projects are read, never built or executed, and nothing leaves your machine during a scan.

Quick start

You need uv, the scanners GapScan wraps, and Ollama for the local AI review. gapscan doctor tells you what is missing.

setup, from a clone of the repository
$ make setup
$ uv run gapscan doctor
$ uv run gapscan data fetch      # once, needs network
$ ollama pull qwen3-coder:30b
$ uv run gapscan serve --open   # local dashboard

Then scan a project, review the findings and write the report:

first scan
$ gapscan scan ./my-project -o scan.json
$ gapscan triage scan.json -t ./my-project --deep-dive
$ gapscan report scan.json --triage triage.json

data fetch is the one network step. It downloads security data from pinned hosts and checks every file against its checksum. [add the public repository link]

How a scan works

Each step hands its output to the next. A step that fails is reported in the result, never hidden.

1Scan

Semgrep with GapScan rules, OSV-Scanner, Trivy, Gitleaks, Checkov, Bandit, or any SARIF file.

2Normalize

One finding format, duplicates merged.

3Map

Each finding tied to a control in the target standard.

4Trace

Request data followed across files to the sink.

5Review

AI review with redacted context, labeled as AI.

6Report

Coverage, gaps, evidence and limits.

Commands

CommandWhat it does
gapscan doctorChecks that the scanners, the model and the security data are ready.
gapscan data fetchDownloads security data once, from pinned hosts, with checksums.
gapscan scan <path> -o scan.jsonRuns the scanners and writes normalized findings. Makes no network call.
gapscan triage scan.json -t <path>AI review of each finding. Add --deep-dive for a slower, deeper pass.
gapscan report scan.json --triage triage.jsonWrites the report with coverage, gaps and AI verdicts.
gapscan run --ai-review --profile <name>Scan, review and report in one step.
gapscan fixProposes a fix, re-scans it, and offers it only when the re-scan is clean.
gapscan serve --openOpens the local dashboard, with the coverage page per standard.
gapscan eval run --targets <set>Runs the evaluation harness on a labeled set, such as benchmark-java.
gapscan eval compareCompares two evaluation runs.

Run gapscan <command> --help for every option.

Gaps and statuses

For each control in the target standard, GapScan gives one of three statuses. None of them is “met”: a person decides what passes.

Gap

The evidence shows the control is not met, for example a request parameter reaching a shell command.

No finding

The control can be checked by code, and nothing was found.

Needs review

The control asks for documents, processes or run-time behaviour that code cannot show.

Every gap carries the control ID, the CWE, the file and line, the data-flow trace where there is one, the AI verdict and the fix. See the sample report.

AI review

The AI review reads each finding with its surrounding code and decides whether it is real. It removes false alarms; it does not find new bugs.

  • Local by default. The model runs through Ollama on your machine or an internal host. qwen3-coder:30b is the tested model. The smallest profile, tiny, is not recommended: it confirms almost everything.
  • Labeled. Every verdict is marked as AI output, with its reasoning, so a reviewer can check it.
  • Checked. Answers must match a fixed format, and deterministic rules run after the model and are never overridden.
  • Guarded. Text in the code that tries to instruct the reviewer is detected. A dismissal of such a finding is never accepted; it goes to a person.
  • Memories. Your team’s past decisions can be given to the model as context. A dismissal made with a memory shown is never final for high or critical findings.

Configuration

Copy config/gapscan.example.toml and edit it. Two settings people change first:

gapscan.toml · example
[scanners]
packs = ["security"]         # only listed packs load

[scanners.semgrep]
rules_path = "./my-rules"    # add your own Semgrep rules

GapScan ships its own Apache-2.0 rule library. The Semgrep community rules are not bundled, because their license forbids use in a competing product. You can opt in for internal use only.

CI, IDE and agents

  • CI: run a scan in any pipeline and stop the build when it finds new gaps.
  • Pull requests: gaps posted as review comments on the changed lines.
  • Pre-commit: a hook that scans staged files before each commit.
  • VS Code: an extension, shipped as a VSIX, that shows gaps in the editor.
  • MCP: a server so coding agents can scan and check their own changes.

Setup steps for each are in docs/ci.md in the repository.

Team server

A self-hosted server for a team: a finding lifecycle, SLA metrics, a REST API and Postgres storage, with Jira, ServiceNow and Slack integrations. It ships as a Docker image and a Helm chart. See docs/team-server.md.

Offline and air-gapped

Offline bundles carry the engine, rules and security data to a machine with no network. Updates arrive as verified bundles. In an air-gapped image, scan, report and doctor work fully offline; triage needs a model endpoint on localhost or an internal host, for example Ollama beside the container. See docs/offline.md.

Languages

371 rules in 9 languages. Scores are catch rate minus false-alarm rate on the held-out half of each benchmark, against the community rules for the same language.

LanguageData flow across filesGapScanCommunity rules
GoPer function+86+16
C#Per function+75+14
JavaScript / TypeScriptYes+61+42
PythonYes+58+20
JavaYes (+62 with the data-flow engine)+47+48
SwiftPer function69% caught6% caught
KotlinPer function65% caught0% caught
PHPPer function+80
Dart / FlutterPer function7% caught0% caught

Dart and PHP coverage is thin, and real iOS apps are much harder than the demo apps behind the Swift score. Full tables are in docs/rules.md.

Hard rules

These hold in every mode and every release.

  1. Scanned code is never built or run.
  2. Nothing leaves the machine during a scan. The only network step is the data download at setup.
  3. Secrets are redacted before anything is stored, shown or sent to a model.
  4. AI output is always labeled as AI, with its reasoning.
  5. GapScan never says a product is compliant or certified. It reports coverage and gaps.

Evaluation

Rules are tuned on one half of each benchmark and scored once on the other half. AI review dismissed under 5% of real bugs on every test set (3 of 110 on the held-out Java set). Run the harness yourself:

evaluation
$ gapscan eval run --targets benchmark-java
$ gapscan eval compare

Method, confidence intervals and limits are in docs/evaluation.md.

Coming in the cloud

Planned, not built yet. These need the cloud service. Join the waitlist to hear when it opens.
  • Coverage view per standard across all projects.
  • Signed proof of fix: a record that a re-scan confirmed the gap is closed.
  • Verdict network: opt-in sharing of redacted fingerprints, never source code.
  • Regression radar: re-checks every project when a new advisory lands.
  • Dynamic evidence: import OWASP ZAP and Nuclei results, for example with gapscan scan --dynamic-report FILE.
  • More standards: NIST SSDF, ISO 27001, SOC 2 and PCI DSS first, then EU, Gulf and Egyptian frameworks with Arabic reports.