Skip to main content

kwaro

A free, open-source security scanner that finds, proves, fixes, and verifies vulnerabilities on your machine.

License: AGPL-3.0 Python: 3.10-3.12 Runtime deps: zero CI: pytest matrix Platform: cross-OS

pip install kwaro  ·  runs on a local model (Ollama) with no API key and no internet, ever.


kwaro helps you find real vulnerabilities in your code by chatting with a local AI agent. No paid APIs, no Docker stacks, no lock-in. It runs anywhere: Windows, macOS, Linux, and WSL.

Most scanners stop at "here is a bug." kwaro goes further, all locally, all for free: it finds a vulnerability, proves it with a runnable proof-of-concept, fixes it with a codebase-aware patch, and verifies the fix by re-scanning. You watch a finding go from "reported" to "proven" to "fixed and verified" in one session, on your own hardware.

kwaro is fully built and released (v0.6.0). Architecture, research, and all design decisions live in docs/. This README is the user-facing entry point.

Why kwaro

  • 100% free by default. Runs on a local model via Ollama. No credit card, no account, fully offline. Paid models (OpenAI, Groq, OpenRouter, and any OpenAI-compatible API) are opt-in via bring-your-own-key.
  • Privacy as a feature, not a footnote. Your code never leaves your machine. With the default local provider, analysis is fully offline. There is no telemetry, no crash reporting, no analytics. This is a hard requirement for fintech, banking, and blockchain teams blocked from cloud scanners.
  • Cross-platform, zero runtime dependencies. Pure Python 3.10+, standard library only for the CLI. One codebase on Windows, macOS, Linux, and WSL.
  • Proof, not opinion. Every finding shows its evidence chain: static rule hit? model confirmation? PoC verified? Confidence is derived from the loop, not asserted by the model.
  • Any codebase, any domain. Generic scanning plus community domain profiles (fintech, blockchain, AI apps). Profiles are plain files anyone can write and submit.
  • Two interfaces, one engine. Talk to it in your terminal (kwaro chat) or in a browser UI (kwaro serve). Same agent, same findings.
  • Open source, AGPL-3.0. Free for everyone, forever. Forkers must stay open.

The loop that makes it different

Find -> Prove -> Fix -> Verify, all on your machine, for free.

  1. Find via static analyzers and model triage.
  2. Prove by generating and (optionally) running a PoC that shows the actual crash.
  3. Fix via the chat agent that edits the file with a real remediation.
  4. Verify by re-scanning the changed file to confirm the bug is gone.

The math (why you can trust it)

kwaro's differentiator is that confidence and termination are derived from the find/prove/fix/verify loop, not asserted by the model. Four primitives make this explicit and honest. All are pure stdlib Python, zero runtime deps, offline-friendly. Full detail and verified examples are in docs/math.md.

  • Bayesian confidence. Each finding starts from a low base rate (candidate flags are mostly noise, prior = 0.05). Evidence collected during prove/verify updates the posterior with Bayes rule. A finding is only reported if its posterior clears the bar. The model's own "I'm 90% sure" number is ignored.
  • Loop-variant termination. The run state has a measure V = unproven + unfixed + unverified. Each pass strictly decreases V until it reaches 0 (or hits a safety cap), so the loop provably terminates. The trace is visible in output.
  • Pipeline graph + trace validator. Find/Prove/Fix/Verify is a directed graph. A completed run must be a legal walk, so prove can never be silently skipped and every finding carries full lineage.
  • SPRT stop rule. Wald's Sequential Probability Ratio Test sets error-rate budgets (alpha = false-positive rate, beta = missed rate) and stops as soon as the accumulated log-likelihood ratio crosses a bound. This controls both error rates by design instead of relying on an arbitrary threshold.

Example from docs/math.md: a real SQLi climbs from posterior 0.05 to 0.89 as static and PoC evidence arrives; a false alarm the model also rated 0.90 collapses to 0.02 because the verify stage found no real exposure. The math decides, not the model.

Features

Feature Status Notes
Static analyzers (secrets, SQLi, XSS, path traversal, weak crypto) shipped pure-Python, zero-dep, CWE-mapped
Domain profiles (generic, fintech, blockchain, ai_app) shipped select which analyzers run
Math spine (Bayes, variant, graph, SPRT) shipped drives confidence, ranking, termination
Pipeline ranking (L3 severity bands + composite confidence) shipped static > model, PoC-verified > unverified
De-duplication by root cause (L4) shipped merges by root cause, not tool output
SARIF 2.1.0 + JSON export shipped carries the math fields under properties
Diff-aware rescan (L9) shipped analyze changed files only
Browser UI via serve extra shipped hand-written bundle, no React build
CI/CD guard (--diff + SARIF) planned GitHub code scanning output
Tree-sitter AST detection optional per-language upgrade, off by default

Install

Pick whichever is easiest on your OS. The CLI has zero third-party dependencies and one pure-Python wheel covers Windows, macOS, and Linux.

# PyPI (all OS)
pip install kwaro          # or: uv tool install kwaro

# macOS / Linux
brew install kwaro         # after: brew tap vip-ultr/kwaro

# Windows
scoop install kwaro        # after: scoop bucket add kwaro https://github.com/vip-ultr/scoop-kwaro

kwaro init                 # detect Ollama, write config (free/offline default)

The browser UI is an optional extra:

pip install "kwaro[serve]" # adds fastapi, uvicorn, websockets

For development from source:

git clone https://github.com/vip-ultr/kwaro
cd kwaro
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,serve]"
pytest                      # runs the suite + the in-repo fixture repo

Quickstart

kwaro init                 # detect Ollama, recommend a local model
kwaro scan ./my-repo       # static-first scan, free, offline
kwaro chat ./my-repo       # conversationally find, prove, fix, verify
kwaro serve                # open the browser UI at http://127.0.0.1:8080

CLI reference

kwaro init                                  # first run: detect Ollama, write config
kwaro scan ./my-repo                        # static scan + math spine, ranked report
kwaro scan ./my-repo --profile fintech      # domain-tuned analyzers
kwaro scan ./my-repo --rescan               # diff-aware: only changed files (L9)
kwaro scan ./my-repo --format sarif         # SARIF 2.1.0 export (math in properties)
kwaro scan ./my-repo --format json          # JSON export (L7 fields + math)
kwaro scan ./my-repo --pocs                  # generate PoC stubs per finding (offline)
kwaro chat ./my-repo                        # interactive loop: model uses tools, then reports
kwaro serve [--port 8080]                   # browser UI (needs the serve extra)

kwaro chat needs a model. With no model configured it falls back to the static analyzer; point it at local Ollama (no key) or a hosted bring-your-own-key provider.

Example scan output

kwaro: scanning ./my-repo (profile: generic, 5 analyzers, math spine on)

5 unique findings (from 5 raw), 0 kept after prove/verify

loop variant trace: 5 -> 5
pipeline graph valid: True (ok)
de-duplicated: 5 raw -> 5 unique

severity | rule                 | file:line        | confidence
---------|----------------------|------------------|-----------
HIGH     | secrets.hardcoded     | app.py:1          | static
HIGH     | injection.sql-concat  | app.py:3          | static
MEDIUM   | xss.innerhtml        | static/bundle.js:5| static
MEDIUM   | traversal.open-userpath| server.go:9      | static
MEDIUM   | auth.weak-hash       | app.py:7          | static

Each finding carries its posterior, SPRT verdict, composite confidence, and PoC state, exposed in the terminal report, the browser UI, and the SARIF/JSON export.

Results (eval, L13)

The seeded fixture tests/fixtures/vuln-repo/ contains one instance of each detector. tests/test_eval.py asserts recall (every seeded rule fires) and flags unexpected rule ids as possible false positives.

Current numbers on the fixture: 100% recall on the 5 seeded rule families (secrets, SQLi, XSS, traversal, weak crypto), 0 unexpected findings. The math spine keeps 0 of 5 static candidates in the "kept" set because offline static evidence alone does not clear the posterior bar or the SPRT REAL verdict, which is the honest behavior until a PoC verifies. As the loop gains prove/verify evidence (see docs/math.md), that SQLi posterior rises to 0.89 and the finding is kept; a false alarm collapses and is dropped. Precision/recall tracking per scan is the product's headline quality metric, not raw "findings found."

Privacy and security posture

kwaro is a local scanner. The SECURITY.md policy is explicit:

  • With the default local provider (Ollama), nothing leaves your machine. No code, snippets, or findings are uploaded anywhere.
  • The only network traffic is what you opt into: a non-local provider, or an explicit version check (off by default).
  • Proof-of-concept execution is off by default. When enabled, it runs in a separate process with a temp directory, no network, and resource/time limits. It is a soft boundary, not a hard sandbox. Run untrusted PoCs in a container or VM you can discard.
  • kwaro complements, not replaces, expert review and mature SAST tools. Model output can be wrong; findings tagged model-only or unverified are lower-confidence by design.

Architecture at a glance

kwaro/
  core/         models, storage (SQLite), workspace, verify (Bayes + SPRT),
                graph (trace validator), loop (variant termination),
                rank (L3 bands + confidence), pipeline (FIND/PROVE/FIX/VERIFY),
                profiles, export (SARIF + JSON)
  analyzers/    base + registry, secrets, injection, xss, traversal, auth, prover
  providers/    base, ollama (offline default), openai-compat (BYOK)
  chat/         agent (tool-calling loop, deterministic validation)
  web/          static bundle (index.html, style.css, app.js), no React build
  serve.py      FastAPI app (lazy import; CLI stays zero-dep)

The CLI stays zero-dependency. FastAPI/uvicorn/websockets load only under kwaro serve. Detailed design and locked decisions: docs/architecture.md, docs/locked-decisions.md.

Development status

Phases 0-6 are shipped and verified (pytest green, 35/35). The CI matrix runs on ubuntu/macos/windows across Python 3.10-3.12. The only remaining pre-1.0 items are a launch demo and the optional PyPI publish step (a maintainer action). See docs/roadmap.md and BUILD.md for the phase history.

Documentation

All planning, research, and locked decisions are in docs/:

Community guidelines: CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md.

Contributing

Contributions of all kinds are welcome: code, domain profiles, docs, bug reports, and ideas. Start with CONTRIBUTING.md. The easiest high-value contribution is a domain profile (see docs/profiles.md). All commits are Developer Certificate of Origin (DCO) signed-off (git commit -s).

License

AGPL-3.0. See LICENSE. Free for everyone, forever; forkers must stay open.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kwaro-0.6.0.tar.gz (138.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kwaro-0.6.0-py3-none-any.whl (59.9 kB view details)

Uploaded Python 3

File details

Details for the file kwaro-0.6.0.tar.gz.

File metadata

  • Download URL: kwaro-0.6.0.tar.gz
  • Upload date:
  • Size: 138.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for kwaro-0.6.0.tar.gz
Algorithm Hash digest
SHA256 8e45ea510befceaf434df1ef7f8c0b2f4b598eb432a62dc4fd7a98b62147620d
MD5 2c127eb493a6cc9c1a7512651cff3ee8
BLAKE2b-256 86aae3adf7a6f41c7f31d59f7b207b8776be1abfa0f5fcd9c5d5aa64dda5e30e

See more details on using hashes here.

File details

Details for the file kwaro-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: kwaro-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 59.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for kwaro-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a0a540fc4b1842c94a21e76178e5cf4f689c78fa5a1975cf4ed5b2481220f39d
MD5 8b4ff0931c012b2126da0aeabfb094a2
BLAKE2b-256 2b2f1e16fde98d7ffe6d3c54d91a578ac7faac98661c7a5df013494fca5b0710

See more details on using hashes here.

Release history Release notifications | RSS feed

0.7.1

2 files

0.7.0

2 files

This release

0.6.0 This release

2 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