flowxai/injection
180
1---2license: apache-2.03library_name: onnx4pipeline_tag: text-classification5tags:6 - prompt-injection7 - jailbreak-detection8 - guardrails9 - onnx10 - multilingual11language: [bg, hr, cs, da, nl, en, et, fi, fr, de, el, hu, ga, it, lv, lt, mt, pl, pt, ro, sk, sl, es, sv, tr, az]12base_model: FacebookAI/xlm-roberta-base13---14 15# injection16 17Prompt injection and jailbreak detection over 26 languages. XLM-RoBERTa base, three18independent labels, INT8 ONNX, CPU. Built for19[`flowx-border`](https://github.com/flowx-ai/border), where it is the T2 `injection`20detector.21 22Labels are multi-label rather than exclusive: `direct_injection`, `indirect_injection`,23`jailbreak`. A single text can be more than one.24 25## What changed in this version, and why it is the headline26 27Three corpora in, the false positives on ordinary customer traffic are gone. Same28architecture and hyperparameters throughout; only the corpus moved.29 30Measured through the shipped configuration at threshold 0.43:31 32| | v3 | v4 | **v5, this one** |33|---|---|---|---|34| ordinary support questions it fires on | 7 of 12 | 1 of 12 | **0 of 12** |35| technical identifiers, at 0.43 | 4 of 4 | 0 of 4 | 1 of 4 |36| technical identifiers, at 0.95 | 4 of 4 | 0 of 4 | **0 of 4** |37| the three canonical attacks | 3 of 3 | 3 of 3 | **3 of 3** |38| mean per-language F1 | 0.9755 | 0.9855 | **0.9891** |39| worst language | – | mt 0.8367 | **mt 0.8817** |40 41v5 added one register, `mundane_account_access`, and it lives in the corpus generator's42shared mundane set so `moderation` and the five single-label classifiers inherit it too. The43gap it fills was invisible because the three registers already there are all prose *about*44things in the third person, a password reset notice or an appointment booking. None of them45was a customer speaking, so "How do I reset my password?" was out of distribution for every46corpus anchored on them, and two detectors independently learned to treat customers as47hostile.48 49**It is not a clean sweep, and the card should say so.** A bare UUID reads50`direct_injection` at 0.944 under v5, clearing 0.43 where v4 had it at zero. It stays below510.95. Net across both shapes v5 is ahead and the regression is real.52 53The previous model read a bare UUID, a git commit hash, a data URI and a sha256 digest as54`jailbreak` or `direct_injection`, and read *"Someone is using my account, how do I lock55it?"* as `direct_injection` at 0.98. Since the detector ships `on_fail: block`, that made the56default policy refuse most of what a support assistant is asked. Both classes of false57positive came from the same corpus property: every benign register was conversational prose,58so an imperative request and a high-entropy identifier were equally out of distribution.59 60## Evaluation61 624,327 held-out rows, threshold 0.43, max_length 96.63 64| label | precision | recall | F1 | FPR |65|---|---|---|---|---|66| `direct_injection` | 0.9528 | 0.9957 | 0.9738 | 0.0057 |67| `indirect_injection` | 0.9709 | 0.9901 | 0.9804 | 0.0021 |68| `jailbreak` | 0.9367 | 0.9850 | 0.9603 | 0.0077 |69 70Mean per-language F1 0.9891. Weakest are `mt` 0.8817, then `ga` 0.9762 and `cs` 0.9767. Maltese is not in XLM-RoBERTa's pretraining set,71and that is a fact about the base model rather than a diagnosis: the same gap in another72detector here closed entirely on corpus size alone, so read 0.8367 as a number to improve73and not as a ceiling.74 75## Corpus76 7745,541 examples: 12,285 attacks and 33,256 benign, 27.0 percent attack share, generated with78`gpt-oss:120b`. 26 languages evenly at 1,656 to 1,690 rows each. 19 registers, including `technical_identifiers` and79`technical_payload`, and four `mundane_*` registers shared with the other classifiers in80this family, of which `mundane_account_access` is v5's addition.81 82276 generated rows were rejected before writing: 127 placeholders, 77 duplicates, 50 in the83wrong script for their language, 22 outside their length band.84 85## Known weakness86 87A bare UUID reads `direct_injection` at 0.944, which clears the shipped 0.43 and not 0.95.88v4 had it at zero, so this is a regression on the technical shape bought alongside a fix to89the account-access one. Both are corpus properties rather than thresholds.90 91The account-access failure v4 could not fix is gone: *"Please cancel my subscription."* read92`direct_injection` at 0.9775 under v4, identical at 0.43 and 0.95 so no threshold reached it.93Two of 35,025 rows matched that phrasing then; v5 has 1,862 rows in the account-access94register and 16 carrying that exact phrasing as benign.95 96## Use it at 0.4397 98The library ships 0.43, above this run's calibrated 0.02. The calibration deliberately is not99adopted: its own report flags 0.02 as the lowest value in the sweep, which compresses scores100toward zero, and macro F1 is 0.9671 even at 0.95, so the sweep is a plateau rather than a101peak. A missed injection costs more than a review, so the shipped value sits well below the102plateau's top without chasing the floor.103 104## Export105 106INT8 with the Gather-only quantisation recipe. 0 of 300 decisions changed against the fp32107graph, probability drift p99 0.00005, max 0.15393, and the max is one row where the p99 is what the gate reads. `onnx/export_manifest.json` carries the108weight hashes.109 110## Licence111 112Apache-2.0. Trained on synthetic data generated for this purpose.113 