Skip to content

Commit 1b96f59

Browse files
ithiria894claude
andcommitted
honest relaunch: defensible claims, fix probe size, scope to unseen-attack generalization, 0.1.5
README/llms/llms-full/COMPETITIVE_LANDSCAPE/FAQ rewritten to the verified evidence: - HackAPrompt (real held-out source, uniform n=3,866): probe 90.3% recall @5% clean-FPR vs same-data TF-IDF 52.8% (88.3% vs 30.3% @1%). Framed as generalization to UNSEEN/novel-wording attacks; text is comparable on familiar wording (disclosed in limitations). - curated cross-source LOSO nested-CV: probe mean AUROC 0.984 vs TF-IDF 0.914 (deepset +0.209 CI[0.168,0.250]); shipped fixed config 0.980. Tool-poisoning partial + SYNTHETIC (MCPTox 0.738 vs 0.545 the one significant win). Within-distribution: tie (~0.79 vs ~0.82). Kill indefensible claims: "First and Only", 96.5/96.6/100%, DeBERTa 0%, "ties fine-tuned DeBERTa 0.957", 0.513-vs-0.172 / 41.5-vs-10.7 4x, "five rounds 93->30", 22KB-as-efficiency-win. Acknowledge prior art (PIShield, TaskTracker, RouteGuard, MindGuard, frontier-lab production probes); claim only the deployment-niche absence ("the only one we found", not "first ever"). Fix probe size: ~10.5 KB -> ~22 KB (matches shipped float64 probe_weights.npz). Delete refuted marketing drafts (docs/articles/*, EVIDENCE_PACKET, intentprobe-vs, three-approaches.png, demo html). MANIFEST.in: ship only honest essentials + prune research/docs junk from the sdist. Add research scripts + _results_published JSON for reproducibility. Tests: 12 passed. Bump 0.1.4 -> 0.1.5. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6f07032 commit 1b96f59

48 files changed

Lines changed: 3822 additions & 1245 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

MANIFEST.in

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,22 @@ include README.md
22
include ROADMAP.md
33
include SECURITY.md
44
include LICENSE
5-
recursive-include docs *.md
5+
include llms.txt
6+
include llms-full.txt
67
recursive-include examples *.py
78
recursive-include intentprobe *.json *.npz
8-
recursive-include research *.json *.md *.txt *.mjs *.ipynb
9+
include docs/RUNTIME_HOOKS.md
10+
include docs/GITHUB_ACTION.md
11+
include docs/DEMO_SCRIPT.md
12+
include docs/COMPETITIVE_LANDSCAPE.md
13+
include docs/FAQ.md
14+
15+
# belt-and-suspenders: never ship research notes, marketing drafts, build junk, or a venv
16+
prune research
17+
prune docs/articles
18+
prune build
19+
prune dist
20+
prune intentprobe.egg-info
21+
recursive-exclude docs *.html
22+
global-exclude *.pyc
23+
global-exclude __pycache__

README.md

Lines changed: 162 additions & 227 deletions
Large diffs are not rendered by default.

docs/COMPETITIVE_LANDSCAPE.md

Lines changed: 322 additions & 206 deletions
Large diffs are not rendered by default.

docs/EVIDENCE_PACKET.md

Lines changed: 0 additions & 99 deletions
This file was deleted.

docs/FAQ.md

Lines changed: 129 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,69 @@ skills, packages, and runtime tool events. It looks for poisoned intent such as
77
credential access, secret exfiltration, hidden persistence, forced tool
88
chaining, or tool hijacking.
99

10+
It is a **research preview**: a local, single-pass, registration-time review
11+
signal, not a hard security boundary.
12+
1013
## What does "activation probing" mean?
1114

12-
IntentProbe runs a tool description through a small frozen local model and reads
13-
the hidden activation state inside the model. Then a small trained probe scores
14-
whether that internal state looks poisoned.
15+
IntentProbe runs a tool description through a small frozen local model
16+
(Qwen2.5-0.5B) and reads the hidden activation state inside the model. Then a
17+
small trained probe scores whether that internal state looks poisoned.
18+
19+
Simple version: most text scanners read the words; an LLM judge asks the model
20+
for a verbal answer. IntentProbe scores the model's internal representation
21+
instead — it reads activations, **not just** the text. That keys the signal off
22+
how the model represents the input rather than the exact surface vocabulary.
1523

16-
Simple version: text scanners read the words. LLM judges ask for an answer.
17-
IntentProbe checks the internal signal before the model says anything.
24+
One honest caveat about the product, not just the method: the activation probe
25+
is the primary signal for `allow` / `warn`, but the `block` tier additionally
26+
requires static-keyword corroboration to control false positives. So a novel,
27+
no-keyword input the probe flags surfaces as `warn`, not `block`. The block tier
28+
is not activation-only.
1829

1930
## Is this the same as asking Qwen if a tool is safe?
2031

2132
No. Asking Qwen "is this safe?" is an LLM-as-judge approach. IntentProbe uses
2233
Qwen2.5-0.5B as a fixed feature extractor and reads hidden activations instead
2334
of trusting the model's generated answer.
2435

25-
We tested the direct-prompt approach. The deterministic label-score version
26-
flagged every clean curated item as poisoned, while the generated-answer
27-
version missed poison and produced many unparseable outputs. See
36+
We tested the direct-prompt approach against the same Qwen2.5-0.5B sensor. The
37+
deterministic label-score baseline flagged every clean curated item as poisoned
38+
(clean false-positive rate = 1.000), and the generated-answer version missed
39+
poison and produced many unparseable outputs. The reproducible baseline is in
2840
[`research/QWEN_PROMPT_JUDGE_BASELINE_2026-06-08.md`](../research/QWEN_PROMPT_JUDGE_BASELINE_2026-06-08.md).
2941

3042
## Why not just use a text classifier?
3143

32-
Text classifiers are useful when unsafe samples have obvious words or patterns.
33-
They struggle when a safe tool and a poisoned tool use almost the same
34-
vocabulary.
44+
A text classifier does well when an attack reuses wording it has already seen.
45+
That is the common case, and there it ties or beats the probe — it is fast and
46+
effective on familiar vocabulary.
3547

36-
On the matched-vocabulary benchmark, the public/source-verifiable DeBERTa
37-
prompt-injection text-classifier baseline scored 0.0% F1, while the
38-
activation-probe method scored 96.6% F1.
48+
The probe's value is generalization. When a text classifier trained on attack
49+
examples then faces attacks from a source it never saw, the learned vocabulary
50+
often does not transfer and recall drops. The probe keys off the model's
51+
internal representation, so it holds up better on attack *sources* and *wording*
52+
it never trained on. See the benchmarks below for the size of that effect (and
53+
where it does not appear).
3954

4055
## Does IntentProbe upload my tool descriptions?
4156

4257
No. IntentProbe runs locally. Scan targets and scan results stay on your
4358
machine.
4459

45-
The first model-backed scan may download Qwen2.5-0.5B once from Hugging Face.
46-
After the model is cached, scans can run from local files.
60+
The first model-backed scan may download Qwen2.5-0.5B once from Hugging Face
61+
(~1 GB). After the model is cached, scans can run from local files.
4762

4863
## What model does v0 use?
4964

5065
The released v0 scanner uses Qwen2.5-0.5B as the frozen local sensor model and
51-
reads layers 13-15. The shipped probe artifact is about 22 KB.
66+
reads mean-pooled mid-layer activations (layers 13-15). The shipped probe
67+
artifact is about 22 KB (float64 logistic-regression weights).
68+
69+
Note on that 22 KB: it is a training-and-storage advantage, not a runtime one.
70+
The probe needs the frozen 0.5B host model to produce activations, so inference
71+
is **heavier** than a standalone text classifier, not lighter. The small probe
72+
head is cheap to train and store; the host model is the cost at scan time.
5273

5374
## Does IntentProbe change or train the base model?
5475

@@ -79,44 +100,115 @@ The runtime output is structured JSON, so a host can consume it directly. See
79100
[`docs/OPERATOR_DECISIONS.md`](OPERATOR_DECISIONS.md) for `allow`, `warn`,
80101
`block`, replay receipts, and suggested operator mappings.
81102

82-
## What are the headline benchmarks?
103+
## What are the benchmarks?
83104

84-
The highest-signal public numbers are:
105+
Everything here is reproducible from [`research/`](../research/), on the
106+
**shipped Qwen2.5-0.5B** artifact. The thesis is generalization to attacks the
107+
probe never trained on — and the results show both where that holds and where it
108+
does not.
85109

86-
| Test | IntentProbe / activation probe | Baseline |
87-
|---|---:|---:|
88-
| Matched-vocabulary F1, n=86 | 96.6% | DeBERTa text classifier 0.0% |
89-
| MCPTox poisoned recall, n=249 | 100.0% | DeBERTa text classifier 19.9% |
90-
| RouteGuard-style external recall, n=2,900 | 41.5% | TF-IDF 10.7% |
91-
| Camouflage suffix evasion | 0/146 evaded | N/A |
110+
**1. Generalization to unseen real attacks (HackAPrompt, n=3,866 uniform-random,
111+
a source neither detector trained on):**
92112

93-
Benchmark artifacts are under [`research/`](../research/).
113+
HackAPrompt is a large set of attacks written by real people in a red-teaming
114+
competition. Neither the probe nor the text baseline saw it during training. It
115+
is positive-only (attacks, no benign), so we report recall at a clean
116+
false-positive rate fixed on the training data — recall at a matched FPR, not
117+
AUROC.
94118

95-
For a compact reviewer packet, see
96-
[`docs/EVIDENCE_PACKET.md`](EVIDENCE_PACKET.md).
119+
| Detector | recall @ 5% clean-FPR | recall @ 1% clean-FPR |
120+
|---|---:|---:|
121+
| Probe (Qwen2.5-0.5B, mean-pooled L13-15) | 90.3% | 88.3% |
122+
| TF-IDF (same training data) | 52.8% | 30.3% |
123+
124+
Same training data, same held-out evaluation, same false-alarm budget. The text
125+
classifier's learned vocabulary does not transfer to wording it never saw, so
126+
recall drops; the probe holds up. Caveat: this is recall at a matched FPR set on
127+
the training clean data, not a full AUROC, and the sample is uniform-random over
128+
the corpus.
129+
130+
**2. Curated cross-source generalization (leave-one-source-out, nested CV, 4 PI
131+
datasets):**
132+
133+
Train on three of {deepset, safeguard, spml, jayavibhav}, test on the held-out
134+
fourth, repeat for each. Model and layer are chosen inside a nested
135+
cross-validation loop, never on the held-out source. 95% bootstrap CIs on the
136+
probe-minus-TF-IDF difference.
137+
138+
| held-out source | probe AUROC | TF-IDF AUROC | difference (95% CI) |
139+
|---|---:|---:|---|
140+
| deepset | 0.941 | 0.732 | +0.209 [0.168, 0.250] significant |
141+
| spml | 0.995 | 0.935 | +0.059 [0.044, 0.077] significant |
142+
| safeguard | 0.999 | 0.993 | +0.006 [0.002, 0.011] significant (at ceiling) |
143+
| jayavibhav | 1.000 | 0.997 | +0.002 [0.000, 0.005] tie (CI touches 0) |
144+
| **mean** | **0.984** | **0.914** | **+0.070** |
145+
146+
deepset is where the gap is widest: TF-IDF's vocabulary does not transfer and it
147+
drops to 0.732, while the probe holds at 0.941. The single **shipped fixed
148+
config** (Qwen2.5-0.5B, mean-pooled concat L13-15, no per-input layer picking)
149+
reaches mean AUROC **0.980** across the same held-out sources (deepset 0.933) —
150+
still above TF-IDF's 0.914, so the advantage is not balanced on one lucky
151+
setting.
152+
153+
**3. Tool poisoning — partial, and on synthetic attacks:**
154+
155+
The cross-source advantage extends to tool poisoning only partially, and on
156+
**synthetic** attacks (no real-human tool-poisoning corpus exists yet, so these
157+
are constructed). Leave-one-corpus-out:
158+
159+
| held-out corpus | probe AUROC | TF-IDF AUROC | difference (95% CI) |
160+
|---|---:|---:|---|
161+
| MCPTox | 0.738 | 0.545 | +0.193 [0.145, 0.241] significant |
162+
| routeguard | 0.640 | 0.582 | non-significant lean |
163+
| synthetic minpairs | 0.494 | 0.498 | both at chance (out of distribution) |
164+
165+
MCPTox is a clear win. The synthetic minimal-pairs set is out of distribution for
166+
both detectors, and both sit at chance on it.
167+
168+
**4. Within-distribution, the text baseline is not blind.** On matched-vocabulary
169+
minimal pairs drawn from the same distribution the probe was trained on, the
170+
probe **ties** TF-IDF (roughly 0.79 vs 0.82). The edge is generalizing to new
171+
sources and new vocabulary, not same-vocabulary detection inside one
172+
distribution.
97173

98174
## Is this a claim about every private cloud scanner?
99175

100-
No. The DeBERTa result is a reproducible comparison against a
101-
public/source-verifiable text-classifier baseline. Private cloud/API scanners
102-
may work well, but their detector artifacts and MCP/tool-poisoning benchmarks
103-
are usually not reproducible by users.
176+
No. The comparison baseline is a TF-IDF text classifier trained on the same data,
177+
plus the public/source-verifiable PI datasets above. Private cloud/API scanners
178+
may work well, but their detector artifacts and MCP/tool-poisoning benchmarks are
179+
usually not reproducible by users, so we do not benchmark against them. The
180+
honest comparison is "activation probe vs same-data text classifier," reproducible
181+
end to end.
182+
183+
## Is this the first activation-probe scanner?
184+
185+
No. Probing model internals for safety is an established line of work: PIShield,
186+
TaskTracker, RouteGuard, MindGuard, and frontier-lab production probes predate or
187+
parallel IntentProbe. IntentProbe is **not** first or only on the technique.
188+
189+
The only-one-we-found niche is the deployment shape, not the method: a tool that
190+
is installable, runs before install, scans the standalone tool/skill/MCP
191+
*description*, and does it on model activations. That is an absence claim ("the
192+
only one we found in this exact shape"), not "first ever." Full source-backed
193+
comparison: [`docs/COMPETITIVE_LANDSCAPE.md`](COMPETITIVE_LANDSCAPE.md).
104194

105195
## Have you tried SAE features?
106196

107197
Yes. SAE features are useful for interpretability and may improve future recall.
108198
The v0 product ships raw Qwen activations because the current raw-activation
109-
artifact is the most complete, lightweight, and reproducible product path today.
199+
artifact is the most complete and reproducible product path today.
110200

111201
SAE is planned as an optional layer for recall improvements and human-readable
112202
explanations.
113203

114204
## Is v0 production-ready?
115205

116-
Use v0 as a pre-install tripwire and runtime warning/blocking layer, not as your
117-
only security boundary. It already catches important same-vocabulary poisoning
118-
cases that text scanners miss, but novel attack families and white-box
119-
adversarial attacks still need more work.
206+
Use v0 as a pre-install review signal and runtime warning/blocking layer, not as
207+
your only security boundary. Its value is generalizing to attacks worded in ways
208+
it never trained on, where a same-data text classifier's recall drops. On
209+
familiar-vocabulary attacks it ties or loses to a text classifier, and on the
210+
synthetic minimal-pairs set both sit at chance. Novel attack families and
211+
white-box adversarial attacks still need more work.
120212

121213
## How do I try it quickly?
122214

0 commit comments

Comments
 (0)