Loading…
Loading…
This is a fine-tuned version of Prompt Injection Guard Small v2.3 by Horizon Labs, as a GGUF for llama.cpp. keepmum modified the model by training it further on coding-agent tool output. It is not made, affiliated with, or endorsed by Horizon Labs. For the original model, its training data and its limitations, see Horizon Labs' model card.
keepmum, a local privacy proxy for coding agents, uses it for its optional check of tool results (files, web pages, MCP replies, command output) for instructions planted for the agent. The unmodified conversion is at keepmum/prompt-injection-guard-small-gguf.
| File | Size | SHA-256 |
|---|---|---|
prompt-injection-guard-small-v2.3-km1.Q8_0.gguf |
164,357,760 bytes | 306b1bf5062ef25b0508c26bc3431318cd3d594f9c3c10b248c19a9e5e566926 |
Same architecture, tokenizer, labels (SAFE, INJECTION) and size as the original: mmBERT-small, 141M parameters, mean pooling.
The original catches attacks in documents well, but missed many in agent tool output. On AgentDojo's tool outputs and on prodnull's repository files it caught a minority at keepmum's settings. It was trained further for one run of 648 steps (2 epochs, learning rate 2e-5 with 6% warmup and linear decay, AdamW, weight decay 0.01, about 32,000 tokens per step, 2,048-token windows), from Horizon Labs' weights at commit 2efc2ed5, on an Apple M5 Pro.
25,555 examples, half injected. Data building: bench/ft_data.py; training: bench/ft_train.py.
| Part | Source (licence) | Label |
|---|---|---|
| Tool results from coding-agent sessions, whole and as short fragments | SWE-chat (ODC-BY), SWE-Hero OpenHands trajectories (CC BY 4.0) | benign |
| The same tool results with a planted instruction (payloads built from goals, framings and wrappers, at the start, middle or end; 8% in other languages, 5% base64) | built from the rows above | injected |
| AgentDojo's banking and slack suites, with and without its attacks | AgentDojo 0.1.34 (MIT) | both |
| MCP tool lists, half with one description poisoned; issue-style bug reports, half with a payload | written for this | both |
| Agent instruction files, install guides, prompt templates in code, writing about attacks | written for this | benign |
| Replay of the original's public training sets | neuralchemy (Apache-2.0), S-Labs (MIT), deepset (Apache-2.0) | both |
Kept out of training, for the test: SWE-chat sessions and SWE-Hero shards that keepmum's benchmark reads, AgentDojo's travel and workspace suites, and all of InjecAgent, LLMail-Inject, CodeIPI, prodnull and keepmum's hand-written set. Training texts equal to a test text were dropped.
keepmum's public benchmark (bench/guard_public.py), as keepmum runs the model: 2,048-token windows, the highest window's P(INJECTION), and a higher threshold for tool results under 200 characters. Each model is at keepmum's Medium setting, where it flags the same share of 2,000 real Claude Code, Codex and Gemini CLI tool results (SWE-chat): 1.7% for the original, 1.5% for this one. Only documents kept out of training are counted.
| Original (0.8; 0.995 under 200 characters) | This model (0.222) | |
|---|---|---|
| AgentDojo, travel and workspace suites (511 attacks) | 80.8% | 91.4% |
| prodnull repository files (2,432 attacks) | 25.0% | 49.5% |
| InjecAgent (600) | 75.5% | 75.2% |
| LLMail-Inject phase 2 (600)* | 98.2% | 98.7% |
| CodeIPI (35) | 48.6% | 40.0% |
| keepmum's hand-written set (144 attacks) | 140 | 140 |
| SWE-Hero tool output flagged (753) | 0.9% | 1.7% |
| prodnull benign files flagged (1,690) | 0.4% | 1.7% |
| Security writing and code that quotes attacks, flagged | 5% | 3% |
* LLMail-Inject is in the original's training data.
bench/results/GUARD.md.The benchmark was put together by one author, and its hand-written part is small. Treat these figures as a comparison between the two models, not as how well either detects injections in general.
Converted with llama.cpp's convert_hf_to_gguf.py at commit 8642541b and quantized to Q8_0, with the same adjustments as the unmodified conversion (tokenizer read as mmBERT's, pre-tokenizer in mmBERT's form, rank pooling with a 2-wide output). Script: bench/horizon_gguf.py --model injection-ft. In llama-server with keepmum's normalizer and windows, it scores keepmum's hand-written holdout as the fine-tuned weights do in PyTorch (AUC 0.992, recall 0.979, no false alarms); 4 of 472 verdicts differ, all within 0.03 of the threshold.
The model's tokenizer normalizes text before the model sees it, and llama.cpp does not. Without it, instructions hidden in invisible characters go unread. Apply it before tokenizing, in this order:
import re, unicodedata
SMUGGLED = {cp: chr(cp - 0xE0000) for cp in range(0xE0020, 0xE007F)} | {cp: chr(cp - 0xE00F0) for cp in range(0xE0110, 0xE016F)}
INVISIBLE = re.compile("[\xad----︀-️"
"\U000e0000-\U000e007f\U000e0100-\U000e01ef̱̅-̸⃐-]")
def normalize(text: str) -> str:
return INVISIBLE.sub("", unicodedata.normalize("NFKC", text.translate(SMUGGLED)))
llama-server -m prompt-injection-guard-small-v2.3-km1.Q8_0.gguf --embedding -c 2048 -ngl 99
curl -s localhost:8080/embeddings -H 'content-type: application/json' \
-d '{"content": ["<tool result text>"], "embd_normalize": -1}'
embd_normalize: -1 returns the raw logits for [SAFE, INJECTION]; their softmax gives P(INJECTION). The server adds <bos> and <eos> around a text input. For a longer text, tokenize it with /tokenize ("add_special": false) and score windows of 2,048 tokens (keepmum overlaps them by 256) and take the highest.
Apache-2.0 (LICENSE). Horizon Labs' NOTICE, with the MIT notice of the base model mmBERT-small, is included unchanged. Modifications by keepmum: the further training described above, and the conversion to GGUF. The training data's licences are in the table above; SWE-chat (ODC-BY) and SWE-Hero (CC BY 4.0) are credited to their authors, SALT-NLP and NVIDIA.
Horizon-Labs/prompt-injection-guard-small