--- title: TextScout emoji: ๐Ÿ›ฐ๏ธ colorFrom: indigo colorTo: blue sdk: docker app_port: 8501 pinned: false license: bigscience-openrail-m --- # TextScout โ€” red-team threat-intel chatbot Ask in plain language. TextScout **retrieves** the matching real record (MITRE ATT&CK groups / techniques / software, CISA KEV + NVD CVEs) and analyzes it with a fine-tuned Llama-3.2-3B (LoRA adapter `Maximuz23/Text-OSINT`). When no record is found โ€” an unknown actor or a non-existent CVE โ€” it **refuses to fabricate** (evidence-gated honesty). **Repo & full write-up:** [github.com/m-maximuz/TextScout](https://github.com/m-maximuz/TextScout) ยท model [`Maximuz23/Text-OSINT`](https://huggingface.co/Maximuz23/Text-OSINT) **Eval** (base Llama 3.2 3B โ†’ fine-tuned, 700-report test + 80-item probe): Honesty F1 0.62 โ†’ **0.99** ยท NER F1 0.60 โ†’ **0.88** ยท Hallucination 0.24 โ†’ **0.09**. **Try it** (use the suggestion chips, or type your own): - `CVE-2021-44228` โ€” a real CVE โ†’ grounded assessment - a fresh ThreatFox IP / domain / hash โ†’ live IOC enrichment (ThreatFox + OTX + VirusTotal) - `APT-Lyrebird-77` or `CVE-9999-0001` โ†’ honest refusal (the differentiator) ## How it works (RAG) 1. Your message is routed to an entity: actor / CVE / technique / malware / report. 2. The matching record is retrieved from the bundled corpus (`corpus.json`, built from real MITRE ATT&CK + CISA KEV/NVD data). **Any CVE not in the snapshot is fetched LIVE from NVD + CISA KEV** โ€” so fresh CVEs that were never in train/valid/test work too. 3. The record is formatted into the exact template the model was trained on; TextScout analyzes it. Empty lookup (unknown actor, non-existent CVE) โ†’ honest refusal. ## Files `Dockerfile` ยท `app.py` ยท `requirements.txt` ยท `corpus.json` (retrieval data) ยท `robot.png`. ## Optional Space secrets - `NVD_API_KEY` โ€” higher NVD rate limit (CVE lookups work without it). - `ABUSE_API_KEY` (abuse.ch unified Auth-Key โ†’ ThreatFox), `OTX_API_KEY`, `VT_API_KEY` โ€” enable **live IOC enrichment**: a pasted IP / domain / hash / URL is looked up across abuse.ch ThreatFox, AlienVault OTX, and VirusTotal, formatted into a `[Threat Report]`, and analyzed. Without them the app still runs (the IOC text passes straight to the model). CISA KEV needs no key (it's a public JSON feed, fetched directly). ## Push updates With the `hf` CLI authenticated, from the `osint-project` root: ```bash hf upload Maximuz23/TextScout demo . --type space --commit-message update ``` The adapter `Maximuz23/Text-OSINT` is public, so no Space secret is needed. ## CPU vs GPU Free CPU runs the 3B model in bf16 (~6 GB) โ€” the first generation is ~30โ€“60s (model load), then faster; lower *Max new tokens* for snappier replies. For instant responses use a **T4 small** (~$0.40/hr): switch the `Dockerfile` base to a CUDA image and uncomment `bitsandbytes` in `requirements.txt`. Pause the Space after the demo. ## Contract โ€” do not drift `app.py`'s `SYSTEM_PROMPT` and record templates mirror `ai-test.ipynb` c03 and `scripts/build_grounded_records.py`. If you retrain and the contract changes, update both or the model goes off-distribution. ## Phase 2 (optional) Swap the bundled `corpus.json` for **live** retrieval (NVD / CISA KEV / MITRE APIs) so the demo reflects current ground truth instead of a snapshot. Needs NVD/OTX keys as secrets.