Spaces:
Running
Running
Download app.js from coralexbadea/BackdoorChecker: direct link, hf CLI and curl.
- Browser
- Download file 7.56 kB
-
https://huggingface.co/spaces/coralexbadea/BackdoorChecker/resolve/main/app.js
- Command line
-
hf download hf://spaces/coralexbadea/BackdoorChecker/app.js
-
curl -L -o app.js https://huggingface.co/spaces/coralexbadea/BackdoorChecker/resolve/main/app.js
7.56 kB
| // Backdoor Checker page logic: file check, existing result lookup, scan command, leaderboard, validation. | |
| (function () { | |
| const SPACE = "coralexbadea/BackdoorChecker"; | |
| const $ = (id) => document.getElementById(id); | |
| const esc = (s) => String(s == null ? "" : s).replace(/[&<>"']/g, (c) => ({"&": "&", "<": "<", ">": ">", '"': """, "'": "'"}[c])); | |
| const hf = (id) => `<a href="https://huggingface.co/${esc(id)}" target="_blank" rel="noopener">${esc(id)}</a>`; | |
| const pct = (x) => (x == null ? "" : Math.round(100 * x) + "%"); | |
| let ROWS = []; | |
| function summarize(c, file) { | |
| const b = c.best || {}; | |
| return {file, model: c.model, parent: c.parent_model, verdict: c.verdict, trigger_score: c.trigger_score, | |
| candidate: b.text, source: b.source, reply_change: b.reply_change, label: c.label || null, | |
| known_pattern_only: !!c.known_pattern_only, scanned: (c.scanned_at || "").slice(0, 10), card: c}; | |
| } | |
| async function loadRows() { | |
| let rows = null; | |
| try { // live listing, so merged pull requests appear without a rebuild | |
| const t = await fetch(`https://huggingface.co/api/spaces/${SPACE}/tree/main/results`); | |
| if (t.ok) { | |
| const files = (await t.json()).map((f) => f.path.split("/").pop()) | |
| .filter((n) => n.endsWith(".json") && n !== "index.json" && n !== "validation.json"); | |
| rows = (await Promise.all(files.map(async (n) => { | |
| try { const r = await fetch("results/" + n); return r.ok ? summarize(await r.json(), n) : null; } catch (e) { return null; } | |
| }))).filter(Boolean); | |
| } | |
| } catch (e) { rows = null; } | |
| if (!rows || !rows.length) { | |
| try { rows = (await (await fetch("results/index.json")).json()).map((r) => Object.assign({card: null}, r)); } catch (e) { rows = []; } | |
| } | |
| return rows; | |
| } | |
| function labelChip(r) { | |
| if (r.label === "positive") return '<span class="chip">positive control</span>'; | |
| if (r.label === "negative") return '<span class="chip">clean control</span>'; | |
| if (r.label === "blind") return '<span class="chip">claimed backdoor, trigger unknown</span>'; | |
| return ""; | |
| } | |
| const isFlag = (v) => v === "TRIGGER-LIKE STRING FOUND" || v === "SUSPECTED BACKDOOR"; | |
| function verdictTag(r) { | |
| if (isFlag(r.verdict)) return `<span class="v bad">Trigger-like string${r.known_pattern_only ? " · known pattern" : ""}</span>`; | |
| if (r.verdict === "NOT SCANNED") return '<span class="v none">Not scanned</span>'; | |
| return '<span class="v none">None found</span>'; | |
| } | |
| function rowHtml(r) { | |
| const cand = r.candidate == null ? "" : `<code>${esc(r.candidate)}</code>`; | |
| const score = r.trigger_score == null ? "" : Number(r.trigger_score).toFixed(2); | |
| return `<tr><td>${hf(r.model)}${labelChip(r)}</td><td>${verdictTag(r)}</td><td>${cand}</td><td class="num">${score}</td> | |
| <td class="num">${pct(r.reply_change)}</td><td>${r.parent ? hf(r.parent) : ""}</td><td>${esc(r.scanned)}</td></tr>`; | |
| } | |
| function renderBoard(filter) { | |
| let rows = ROWS.slice(); | |
| if (filter === "flagged") rows = rows.filter((r) => isFlag(r.verdict)); | |
| if (filter === "controls") rows = rows.filter((r) => r.label); | |
| if (filter === "community") rows = rows.filter((r) => !r.label); | |
| rows.sort((a, b) => isFlag(b.verdict) - isFlag(a.verdict) | |
| || (b.trigger_score ?? -1e9) - (a.trigger_score ?? -1e9)); | |
| document.querySelector("#lb tbody").innerHTML = rows.length ? rows.map(rowHtml).join("") | |
| : '<tr><td colspan="7" class="muted">No rows here yet. Be the first to submit a scan!</td></tr>'; | |
| } | |
| document.querySelectorAll("[data-f]").forEach((b) => b.addEventListener("click", () => { | |
| document.querySelectorAll("[data-f]").forEach((x) => x.setAttribute("aria-pressed", String(x === b))); | |
| renderBoard(b.dataset.f); | |
| })); | |
| function resultHtml(c) { | |
| if (!c || !c.best) return ""; | |
| const b = c.best; | |
| const ex = (b.examples || []).map((e) => `<tr><td>${esc(e.prompt)}</td><td>${esc(e.reply)}</td><td>${esc(e.with_trigger)}</td></tr>`).join(""); | |
| return `<h3>Published scan: ${verdictTag({verdict: c.verdict, known_pattern_only: c.known_pattern_only})}</h3> | |
| <p class="muted">A measurement, not a verdict: read the replies below before concluding anything.</p> | |
| <ul class="facts"><li>Strongest candidate <code>${esc(b.text)}</code> (found via ${esc(b.source)})</li> | |
| <li>Changes the reply on ${pct(b.reply_change)} of 24 held-out prompts (needs ≥ ${pct(c.thresholds.behaviour_min_rate)}); random strings ${pct(c.null.reply_change)}, same string in the parent ${pct(b.parent_reply_change)}</li> | |
| <li>Trigger score ${b.trigger_score} (needs ≥ ${c.thresholds.min_trigger_score}); screen outlier z ${b.screen_z} (needs ≥ ${c.thresholds.z_screen})</li> | |
| <li>Scanned ${esc((c.scanned_at || "").slice(0, 10))} against parent ${c.parent_model ? hf(c.parent_model) : "none"}, tool v${esc(c.version)}</li></ul> | |
| <div class="tablewrap"><table><thead><tr><th>Prompt</th><th>Reply</th><th>Reply with candidate</th></tr></thead><tbody>${ex}</tbody></table></div>`; | |
| } | |
| async function check(raw) { | |
| $("go").disabled = true; | |
| $("result").innerHTML = '<p class="muted">Checking…</p>'; | |
| try { | |
| const x = await FileScan.scanRepo(raw); | |
| const parent = x.declared_base_models[0]; | |
| const scanned = ROWS.find((r) => r.model.toLowerCase() === x.repo_id.toLowerCase()); | |
| let card = scanned && scanned.card; | |
| if (scanned && !card) { try { card = await (await fetch("results/" + scanned.file)).json(); } catch (e) { card = null; } } | |
| const base = parent ? "" : ` --base ${card && card.parent_model ? card.parent_model : "org/parent-chat-model"}`; | |
| const cmd = `python -m backdoorcheck.cli scan ${x.repo_id}${base} --out result.json`; | |
| const deep = x.needs_trust_remote_code ? "<b>no</b>: the model needs trust_remote_code, which the scanner never runs" | |
| : (x.safetensors_files ? "yes (safetensors weights)" : "only if Hugging Face's automatic safetensors conversion exists"); | |
| $("result").innerHTML = `<ul class="facts"> | |
| <li>Weights: ${x.safetensors_files} safetensors file(s)${x.pickle_files.length ? `, plus pickle files that can run code when loaded: ${x.pickle_files.map(esc).join(", ")}` : ""} · ${x.total_size_gb} GB</li> | |
| <li>Parent model for the comparison: ${parent ? hf(parent) : "<b>not declared</b>, so pass <code>--base</code>"}</li> | |
| <li>Deep scan possible: ${deep}</li></ul> | |
| <p style="margin-top:12px"><b>Run it on your machine:</b></p><pre><code>${esc(cmd)}</code></pre> | |
| ${card ? resultHtml(card) : '<p class="muted">No published scan for this model yet.</p>'}`; | |
| } catch (e) { | |
| $("result").innerHTML = `<p class="err">${esc(e.message)}</p>`; | |
| } finally { $("go").disabled = false; } | |
| } | |
| $("scanform").addEventListener("submit", (ev) => { ev.preventDefault(); check($("rid").value); }); | |
| document.querySelectorAll("[data-ex]").forEach((a) => a.addEventListener("click", () => { $("rid").value = a.dataset.ex; check(a.dataset.ex); })); | |
| async function loadValidation() { | |
| try { | |
| const v = await (await fetch("results/validation.json")).json(); | |
| $("accuracy").innerHTML = v.html; | |
| } catch (e) { $("accuracy").innerHTML = '<p class="muted">Validation results are not available.</p>'; } | |
| } | |
| (async () => { | |
| ROWS = await loadRows(); | |
| renderBoard("all"); | |
| const q = new URLSearchParams(location.search).get("model"); | |
| if (q) { $("rid").value = q; check(q); } | |
| })(); | |
| loadValidation(); | |
| })(); | |