Spaces:
Running on Zero
Running on Zero
repo-audit: detection via HF Inference (Qwen3-Coder-480B), 7B keeps refutation
Browse files
README.md
CHANGED
|
@@ -42,10 +42,11 @@ input): only the real one survives, with its PoC.
|
|
| 42 |
- **Whole-repo, split by model size, both via HF Inference** — detection on
|
| 43 |
[Qwen3-Coder-480B-A35B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct): a
|
| 44 |
whole-file view follows a long source→sink data-flow (an injection can be ~200 lines from its
|
| 45 |
-
sink) the small model misses. Refutation on
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
|
|
|
| 49 |
|
| 50 |
Paste any snippet, pick the language, audit. All example code is fictional and **intentionally
|
| 51 |
vulnerable** — it's the test set. This is a **defensive / educational** demo, not a production scanner.
|
|
|
|
| 42 |
- **Whole-repo, split by model size, both via HF Inference** — detection on
|
| 43 |
[Qwen3-Coder-480B-A35B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct): a
|
| 44 |
whole-file view follows a long source→sink data-flow (an injection can be ~200 lines from its
|
| 45 |
+
sink) the small model misses. Refutation on **Qwen2.5-Coder-32B** over a **bounded, line-numbered
|
| 46 |
+
window** around each candidate: it must *credit* real sanitization (prepared statements, allow-lists,
|
| 47 |
+
casts) to drop false positives — a 7B refuter can't and confirms almost everything — while not being
|
| 48 |
+
fooled by `file_exists`/`isset` guards (which don't stop an LFI). Both stages off-GPU, so a whole-repo
|
| 49 |
+
scan has no length limit.
|
| 50 |
|
| 51 |
Paste any snippet, pick the language, audit. All example code is fictional and **intentionally
|
| 52 |
vulnerable** — it's the test set. This is a **defensive / educational** demo, not a production scanner.
|
app.py
CHANGED
|
@@ -38,19 +38,20 @@ MAX_FINDINGS = int(os.environ.get("MAX_FINDINGS", "5"))
|
|
| 38 |
# The repo audit runs BOTH stages on HF Inference by default:
|
| 39 |
# - detection on a LARGE model (480B): whole-file detection needs a wide view + a long data-flow
|
| 40 |
# (source→sink can be ~200 lines apart, e.g. an LFI through an object), which the 7B misses.
|
| 41 |
-
# - refutation on a
|
| 42 |
-
#
|
|
|
|
| 43 |
# Both off-GPU ⇒ a long whole-repo scan needs NO ZeroGPU reservation, so there is no proxy-token to
|
| 44 |
# expire mid-scan (the limit that capped multi-file scans). ZeroGPU is the no-token fallback.
|
| 45 |
DETECT_BACKEND = os.environ.get("DETECT_BACKEND", "hf_inference").strip().lower()
|
| 46 |
REFUTE_BACKEND = os.environ.get("REFUTE_BACKEND", "hf_inference").strip().lower()
|
| 47 |
HF_INFERENCE_MODEL = os.environ.get("HF_INFERENCE_MODEL", "Qwen/Qwen3-Coder-480B-A35B-Instruct") # detect (large)
|
| 48 |
-
HF_REFUTE_MODEL = os.environ.get("HF_REFUTE_MODEL", "Qwen/Qwen2.5-Coder-
|
| 49 |
HF_TOKEN = os.environ.get("HF_TOKEN")
|
| 50 |
# Rough $/1M-token figure for cost *logging* only (the real cost shows on the HF billing dashboard).
|
| 51 |
USD_PER_MTOK = float(os.environ.get("HF_INFERENCE_USD_PER_MTOK", "0.9"))
|
| 52 |
REFUTE_CHUNK = int(os.environ.get("REFUTE_CHUNK", "6")) # candidates per ZeroGPU call (zerogpu fallback only)
|
| 53 |
-
REFUTE_CTX = int(os.environ.get("REFUTE_CTX", "
|
| 54 |
|
| 55 |
_inf_client = InferenceClient(token=HF_TOKEN) if HF_TOKEN else None
|
| 56 |
if _inf_client is None: # no token → both repo stages fall back to the local 7B on ZeroGPU
|
|
@@ -237,8 +238,8 @@ Audit a **whole public repository**. It clones shallow (or unpacks your `.zip`)
|
|
| 237 |
sandbox, ranks the code files **by security relevance**, and scans the top ones **file-by-file with
|
| 238 |
streaming** — two stages **split by model size**: detection runs on a large model
|
| 239 |
(**Qwen3-Coder-480B**) that can follow a long source→sink data-flow across a whole file, then each
|
| 240 |
-
candidate is **adversarially refuted by
|
| 241 |
-
|
| 242 |
**Static analysis only — the target code is never executed. Public / authorized repos only.**
|
| 243 |
|
| 244 |
⏱️ A scan uses HF Inference credits (both stages, off-GPU — no scan-length limit). Try
|
|
@@ -248,7 +249,7 @@ false positives are dropped — both via **HF Inference**.
|
|
| 248 |
ABOUT = """
|
| 249 |
---
|
| 250 |
Snippet: **Qwen2.5-Coder-7B** on **ZeroGPU** · whole-repo: detect **Qwen3-Coder-480B** + refute
|
| 251 |
-
**Qwen2.5-Coder-
|
| 252 |
[Ferr0](https://huggingface.co/Ferr0) · [pixelium.win](https://pixelium.win) · [GitHub](https://github.com/ferr079)
|
| 253 |
"""
|
| 254 |
|
|
|
|
| 38 |
# The repo audit runs BOTH stages on HF Inference by default:
|
| 39 |
# - detection on a LARGE model (480B): whole-file detection needs a wide view + a long data-flow
|
| 40 |
# (source→sink can be ~200 lines apart, e.g. an LFI through an object), which the 7B misses.
|
| 41 |
+
# - refutation on a CAPABLE model (32B) over a bounded window (±REFUTE_CTX): the refuter must CREDIT
|
| 42 |
+
# real sanitization (prepared statements, allow-lists, casts) — a 7B refuter can't, so it drowns the
|
| 43 |
+
# report in false positives — while not being fooled by file_exists/isset guards (see REFUTE_SYS).
|
| 44 |
# Both off-GPU ⇒ a long whole-repo scan needs NO ZeroGPU reservation, so there is no proxy-token to
|
| 45 |
# expire mid-scan (the limit that capped multi-file scans). ZeroGPU is the no-token fallback.
|
| 46 |
DETECT_BACKEND = os.environ.get("DETECT_BACKEND", "hf_inference").strip().lower()
|
| 47 |
REFUTE_BACKEND = os.environ.get("REFUTE_BACKEND", "hf_inference").strip().lower()
|
| 48 |
HF_INFERENCE_MODEL = os.environ.get("HF_INFERENCE_MODEL", "Qwen/Qwen3-Coder-480B-A35B-Instruct") # detect (large)
|
| 49 |
+
HF_REFUTE_MODEL = os.environ.get("HF_REFUTE_MODEL", "Qwen/Qwen2.5-Coder-32B-Instruct") # refute (judge — needs to credit real sanitization)
|
| 50 |
HF_TOKEN = os.environ.get("HF_TOKEN")
|
| 51 |
# Rough $/1M-token figure for cost *logging* only (the real cost shows on the HF billing dashboard).
|
| 52 |
USD_PER_MTOK = float(os.environ.get("HF_INFERENCE_USD_PER_MTOK", "0.9"))
|
| 53 |
REFUTE_CHUNK = int(os.environ.get("REFUTE_CHUNK", "6")) # candidates per ZeroGPU call (zerogpu fallback only)
|
| 54 |
+
REFUTE_CTX = int(os.environ.get("REFUTE_CTX", "60")) # ± lines of context for refutation (enough to see the local sanitization, not the whole file)
|
| 55 |
|
| 56 |
_inf_client = InferenceClient(token=HF_TOKEN) if HF_TOKEN else None
|
| 57 |
if _inf_client is None: # no token → both repo stages fall back to the local 7B on ZeroGPU
|
|
|
|
| 238 |
sandbox, ranks the code files **by security relevance**, and scans the top ones **file-by-file with
|
| 239 |
streaming** — two stages **split by model size**: detection runs on a large model
|
| 240 |
(**Qwen3-Coder-480B**) that can follow a long source→sink data-flow across a whole file, then each
|
| 241 |
+
candidate is **adversarially refuted by Qwen2.5-Coder-32B on a bounded context** — it credits real
|
| 242 |
+
sanitization (prepared statements, allow-lists) and drops false positives — both via **HF Inference**.
|
| 243 |
**Static analysis only — the target code is never executed. Public / authorized repos only.**
|
| 244 |
|
| 245 |
⏱️ A scan uses HF Inference credits (both stages, off-GPU — no scan-length limit). Try
|
|
|
|
| 249 |
ABOUT = """
|
| 250 |
---
|
| 251 |
Snippet: **Qwen2.5-Coder-7B** on **ZeroGPU** · whole-repo: detect **Qwen3-Coder-480B** + refute
|
| 252 |
+
**Qwen2.5-Coder-32B**, both via **HF Inference** · static analysis, no code execution, no secrets · built by
|
| 253 |
[Ferr0](https://huggingface.co/Ferr0) · [pixelium.win](https://pixelium.win) · [GitHub](https://github.com/ferr079)
|
| 254 |
"""
|
| 255 |
|
engine.py
CHANGED
|
@@ -17,20 +17,23 @@ DETECT_SYS = (
|
|
| 17 |
"ignore pure style, quality or error-handling nits. Use 1-based line numbers."
|
| 18 |
)
|
| 19 |
REFUTE_SYS = (
|
| 20 |
-
"You are an exploit analyst verifying ONE claimed vulnerability in the given code. Decide "
|
| 21 |
-
"
|
| 22 |
-
"- EXPLOITABLE (exploitable=true):
|
| 23 |
-
"
|
| 24 |
-
"
|
| 25 |
-
"
|
| 26 |
-
"
|
| 27 |
-
"sink is unreachable
|
| 28 |
-
"
|
| 29 |
-
"
|
| 30 |
-
"
|
| 31 |
-
"
|
| 32 |
-
"
|
| 33 |
-
"
|
|
|
|
|
|
|
|
|
|
| 34 |
)
|
| 35 |
|
| 36 |
SEV = {"critical": "🔴", "high": "🟠", "medium": "🟡", "low": "⚪"}
|
|
|
|
| 17 |
"ignore pure style, quality or error-handling nits. Use 1-based line numbers."
|
| 18 |
)
|
| 19 |
REFUTE_SYS = (
|
| 20 |
+
"You are an exploit analyst verifying ONE claimed vulnerability in the given code. Decide if it "
|
| 21 |
+
"is GENUINELY exploitable. Judge ONLY what the code shows.\n"
|
| 22 |
+
"- EXPLOITABLE (exploitable=true): attacker-controlled input reaches the dangerous sink with NO "
|
| 23 |
+
"adequate sanitization in between; give a concrete proof-of-concept input.\n"
|
| 24 |
+
"- FALSE POSITIVE (exploitable=false): adequate protection on the value before the sink — a "
|
| 25 |
+
"prepared/parameterized query, an allow-list of permitted values, a cast to a safe type, proper "
|
| 26 |
+
"escaping (escapeshellarg, htmlspecialchars), or strict value validation (is_numeric on the whole "
|
| 27 |
+
"value). Also FP if the sink is unreachable/dead code, or the input is not attacker-controlled. "
|
| 28 |
+
"If a proper sanitization like that is visible, it IS a false positive — say so.\n"
|
| 29 |
+
"Two traps, do NOT fall for them:\n"
|
| 30 |
+
"1. An EXISTENCE/presence check is NOT sanitization. If attacker input is used to build a path "
|
| 31 |
+
"passed to include/require/file_get_contents/fopen/readfile — EVEN with a fixed directory prefix, "
|
| 32 |
+
"a forced extension (.php), or a file_exists()/is_file() guard — it IS EXPLOITABLE (path traversal "
|
| 33 |
+
"/ LFI): the attacker still controls which file loads, and such prefix/suffix/existence constraints "
|
| 34 |
+
"are routinely bypassed (../, encoded traversal, existing sensitive files).\n"
|
| 35 |
+
"2. isset/empty/strlen do not stop injection.\n"
|
| 36 |
+
"If exploitable, set exploitable=true and give the PoC input."
|
| 37 |
)
|
| 38 |
|
| 39 |
SEV = {"critical": "🔴", "high": "🟠", "medium": "🟡", "low": "⚪"}
|