A two-LLM, refute-first agentic source-code vulnerability scanner — wide-net navigate, skeptical refute, jailed in docker. Bring your own LLM.
Project description
refutescan
A two-LLM, refute-first agentic source-code vulnerability scanner.
Most LLM code scanners have the same problem: they hallucinate. Point a model at a repo and it will confidently report SQL injection in a parameterized query and SSRF behind an allowlist. The noise buries the real bugs.
refutescan splits the job across two models:
- Navigate (wide net). A fast tool-calling model explores the repo with
read-only tools (
list_dir/read_file/grep), traces untrusted input toward dangerous sinks, and records candidate findings. It's cheap and it over-reports on purpose. - Refute (skeptic). A stronger model re-reads the actual code slice around each candidate from disk — ground truth, not the navigator's paraphrase — and is prompted to refute it. Sanitized? Parameterized? Gated by auth? Not reachable? It's culled, with the reason kept. Only what survives is reported.
You get the recall of an agentic scanner without the false-positive flood.
Every scan runs jailed in an ephemeral docker sandbox by default: git URLs are cloned inside a container (no host mounts), then audited in a second container with no network, read-only, no capabilities, non-root, and only the repo mounted. A hostile repo (malicious submodule, hook, symlink) touches neither your filesystem nor the network.
Install
pip install refutescan # core kernel
pip install 'refutescan[openai]' # + the OpenAI adapter for the CLI
For sandboxed scans (recommended), build the jail image once:
refutescan-build-sandbox
(Requires Docker. Without it, refutescan falls back to a guarded in-process scan.)
CLI
export OPENAI_API_KEY=sk-...
refutescan https://github.com/owner/repo
refutescan ./path/to/local/repo --judge-model gpt-4o --json
Exit code is non-zero when confirmed findings exist, so it drops straight into CI.
Library
from refutescan import scan, ScanConfig
from refutescan.adapters import openai_navigator_factory, openai_judge_factory
result = scan(
"https://github.com/owner/repo",
navigator_factory=openai_navigator_factory("gpt-4o-mini"),
judge_factory=openai_judge_factory("gpt-4o"),
config=ScanConfig(sandbox="docker"), # auto | docker | inprocess
progress=lambda phase: print(phase),
)
for f in result.findings:
print(f["severity"], f["title"], f"{f['file']}:{f['line']}")
print(" ", f["reasoning"])
print(" fix:", f["recommendation"])
result.culled holds the refuted candidates with the reason each was rejected —
useful for tuning and for trusting the tool.
Bring your own model
refutescan never imports a provider SDK in its core. Pass any LangChain-style chat model through two factories:
navigator_factory() -> chat_model— supports.bind_tools(...)+.invoke(...)judge_factory() -> judge(prompt, schema) -> instance— one structured-output call
So a local model (vLLM/Ollama via the OpenAI shim, --base-url), Anthropic,
Azure OpenAI, or a corporate gateway all work — wire the factory and go. See
refutescan/providers.py.
What it is and isn't
- Is: an agentic, read-only, false-positive-resistant first-pass auditor for the common web-app vuln classes (injection, authz/IDOR, SSRF, path traversal, unsafe deserialization, hardcoded secrets, weak crypto, XSS, auth flaws).
- Isn't: a replacement for a full SAST suite, a proof of exploitability, or a patch generator. It finds and explains; a human confirms and fixes.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file refutescan-0.1.0.tar.gz.
File metadata
- Download URL: refutescan-0.1.0.tar.gz
- Upload date:
- Size: 29.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
255aa752429007c3f2704b77e4891a9dacf904f970a24cb70ae78838c82134c0
|
|
| MD5 |
53cb1d4e606751c8ebadf83292961b3e
|
|
| BLAKE2b-256 |
f82f111671f5d92650751e68d5e93134d02116af1359da0e638924086af71b1c
|
Provenance
The following attestation bundles were made for refutescan-0.1.0.tar.gz:
Publisher:
release.yml on vinayvobbili/refutescan
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
refutescan-0.1.0.tar.gz -
Subject digest:
255aa752429007c3f2704b77e4891a9dacf904f970a24cb70ae78838c82134c0 - Sigstore transparency entry: 1971778943
- Sigstore integration time:
-
Permalink:
vinayvobbili/refutescan@d8affe35e4c84b884c2f78e84b3e71bb25932da7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/vinayvobbili
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d8affe35e4c84b884c2f78e84b3e71bb25932da7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file refutescan-0.1.0-py3-none-any.whl.
File metadata
- Download URL: refutescan-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17de1e7504616656df3866e20adae3fdd7d4c0b1d8583a9d643f9164c46a6f24
|
|
| MD5 |
3254fb754a34bf55c91ccd12e24bbe60
|
|
| BLAKE2b-256 |
2d6d0192afff4bad893f063a610d1fcee48e7653631ecdda4ce2a6fb72df97ae
|
Provenance
The following attestation bundles were made for refutescan-0.1.0-py3-none-any.whl:
Publisher:
release.yml on vinayvobbili/refutescan
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
refutescan-0.1.0-py3-none-any.whl -
Subject digest:
17de1e7504616656df3866e20adae3fdd7d4c0b1d8583a9d643f9164c46a6f24 - Sigstore transparency entry: 1971779019
- Sigstore integration time:
-
Permalink:
vinayvobbili/refutescan@d8affe35e4c84b884c2f78e84b3e71bb25932da7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/vinayvobbili
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d8affe35e4c84b884c2f78e84b3e71bb25932da7 -
Trigger Event:
push
-
Statement type: