Spaces:
Running
Running
Download scan.js from coralexbadea/BackdoorChecker: direct link, hf CLI and curl.
- Browser
- Download file 3.88 kB
-
https://huggingface.co/spaces/coralexbadea/BackdoorChecker/resolve/main/scan.js
- Command line
-
hf download hf://spaces/coralexbadea/BackdoorChecker/scan.js
-
curl -L -o scan.js https://huggingface.co/spaces/coralexbadea/BackdoorChecker/resolve/main/scan.js
3.88 kB
| // Backdoor Checker instant file scan (shared with SafetyCard), runs in the browser (and in Node for tests). | |
| // A direct port of safetycard/artifacts.py: same grade rules, downloads no weights. | |
| (function (root) { | |
| const PICKLE_EXT = [".bin", ".pt", ".pth", ".ckpt", ".pkl", ".pickle", ".joblib"]; | |
| const NON_WEIGHT_BIN = ["training_args.bin"]; | |
| const GRADES = { | |
| A: "Safetensors/GGUF weights only, no custom code required.", | |
| B: "Safe weight format, but the model needs trust_remote_code (runs the author's Python).", | |
| C: "Safe weights present, plus pickle files that can run code if loaded.", | |
| F: "Weights only in pickle format: loading them can execute arbitrary code.", | |
| }; | |
| function normalizeId(s) { | |
| return (s || "").trim().replace(/^https?:\/\/huggingface\.co\//, "").replace(/\/+$/, "") | |
| .split("/").slice(0, 2).join("/"); | |
| } | |
| async function scanRepo(repoIdRaw, fetchFn) { | |
| const f = fetchFn || root.fetch.bind(root); | |
| const repoId = normalizeId(repoIdRaw); | |
| if (!/^[\w.-]+\/[\w.-]+$/.test(repoId)) throw new Error("Use the form org/model, e.g. Qwen/Qwen2.5-1.5B-Instruct"); | |
| const r = await f(`https://huggingface.co/api/models/${repoId}?blobs=true&securityStatus=true`); | |
| if (r.status === 401 || r.status === 404) throw new Error(`Model "${repoId}" not found, or it is private.`); | |
| if (!r.ok) throw new Error(`Hub API error ${r.status}`); | |
| const info = await r.json(); | |
| const sib = info.siblings || []; | |
| const names = sib.map((s) => s.rfilename); | |
| const lower = (n) => n.toLowerCase(); | |
| const pickles = names.filter((n) => PICKLE_EXT.some((e) => lower(n).endsWith(e))); | |
| const safetensors = names.filter((n) => lower(n).endsWith(".safetensors")); | |
| const gguf = names.filter((n) => lower(n).endsWith(".gguf")); | |
| const pyFiles = names.filter((n) => n.endsWith(".py")); | |
| let autoMap = (info.config && info.config.auto_map) || null; | |
| let configNote = null; | |
| if (!autoMap && names.includes("config.json")) { | |
| try { | |
| const c = await f(`https://huggingface.co/${repoId}/resolve/main/config.json`); | |
| if (c.ok) autoMap = (await c.json()).auto_map || null; | |
| else configNote = "config.json could not be read (gated model?): remote-code check incomplete."; | |
| } catch (e) { | |
| configNote = "config.json could not be read: remote-code check incomplete."; | |
| } | |
| } | |
| const needsRemoteCode = !!autoMap; | |
| const weightPickles = pickles.filter((p) => !NON_WEIGHT_BIN.includes(p.split("/").pop())); | |
| const safe = safetensors.length > 0 || gguf.length > 0; | |
| let grade; | |
| if (safe && pickles.length === 0) grade = needsRemoteCode ? "B" : "A"; | |
| else if (safe && pickles.length > 0) grade = "C"; | |
| else if (weightPickles.length > 0) grade = "F"; | |
| else grade = needsRemoteCode ? "B" : "A"; | |
| const card = info.cardData || {}; | |
| const bm = card.base_model; | |
| const sec = info.securityRepoStatus; | |
| return { | |
| repo_id: repoId, | |
| revision: info.sha, | |
| grade, | |
| grade_meaning: GRADES[grade], | |
| pickle_files: pickles, | |
| safetensors_files: safetensors.length, | |
| gguf_files: gguf.length, | |
| custom_code_files: pyFiles, | |
| needs_trust_remote_code: needsRemoteCode, | |
| declared_base_models: bm ? (Array.isArray(bm) ? bm : [bm]) : [], | |
| license: card.license || null, | |
| gated: info.gated || false, | |
| hf_security_scan: sec ? { scans_done: sec.scansDone, files_with_issues: (sec.filesWithIssues || []).map((x) => x.path) } : null, | |
| total_size_gb: Math.round(sib.reduce((a, s) => a + (s.size || 0), 0) / 1e7) / 100, | |
| deep_scan_supported: safetensors.length > 0 && !needsRemoteCode, | |
| note: configNote, | |
| }; | |
| } | |
| root.FileScan = { scanRepo, normalizeId, GRADES }; | |
| if (typeof module !== "undefined") module.exports = root.FileScan; | |
| })(typeof globalThis !== "undefined" ? globalThis : this); | |