Probing the Prefill: Detecting Code Vulnerabilities via Latent Activations
Organizations: Wrynx Inc.
Abstract
LLM-based code generation is now embedded in mission-critical pipelines, but defenses against vulnerable output remain post-hoc -- static analyzers, fine-tuned classifiers, or an LLM judge that screen completed code, ignoring the generating model's own internal state. We test a narrower, directly measurable question: when an LLM reads a piece of C/C++ code as context, do its hidden activations already carry a signal about that code's vulnerability status? We extract last prefill token activations from four LLMs (Granite-4.1-8B, Qwen3.5-9B, Qwen3.6-27B, Gemma-4-12B) across three model families and train MLP probes on these activations. We evaluate them on four function-level C/C++ benchmarks (Devign, Big-Vul, Draper VDISC, PrimeVul). Our probes achieve 41.7% average F1 using 13.4--16.0M-parameter probes -- under 0.2% of base-model size. On Devign, the best probe (Qwen3.5-9B, 68.8% F1) matches the published fine-tuned-classifier SOTA (67.9%) despite reading only a frozen, general-purpose LLM's activations; on the harder, more imbalanced benchmarks (Big-Vul, Draper VDISC, PrimeVul) probes trail SOTA substantially. This is early evidence that a coding LLM's own representation of arbitrary code is informative about that code's vulnerability status, motivating further work toward lightweight, model-native vulnerability screening.
Figures & tables
| Model | Params | (hidden dim) | Layers |
|---|---|---|---|
| Granite-4.1-8B | 8B | 4096 | 40 |
| Qwen3.5-9B | 9B | 4096 | 32 |
| Qwen3.6-27B | 27B | 5120 | 64 |
| Gemma-4-12B | 12B | 3840 | 48 |
| Dataset | Size | Vuln. % | SOTA F1 | Labeling |
|---|---|---|---|---|
| Devign [ 24 ] | 27K | 46% | 67.9% | manual review |
| Big-Vul [ 25 ] | 217K | 5.8% | 96.5%* | CVE/patch mining |
| Draper VDISC [ 26 ] | 1.27M | 9.6% | 60.9% | static-analyzer |
| PrimeVul [ 23 ] | 236K | 3% | 24.5%* | auto-labeling |
| Layer | In | Out | Activation |
|---|---|---|---|
| 1 | (Table I ) | 2048 | GELU + Dropout( ) |
| 2 | 2048 | 2048 | GELU + Dropout( ) |
| 3 | 2048 | 512 | GELU + Dropout( ) |
| 4 | 512 | 512 | GELU + Dropout( ) |
| 5 | 512 | 64 | GELU + Dropout( ) |
| 6 | 64 | 1 | (raw logit; sigmoid applied by the loss) |
| Devign | Big-Vul | Draper VDISC | PrimeVul | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Model | P | R | F1 | P | R | F1 | P | R | F1 | P | R | F1 |
| Granite-4.1-8B | 58.15 | 75.63 | 65.74 | 43.26 | 46.00 | 44.59 | 24.15 | 41.48 | 30.53 † | 27.48 | 15.12 | 19.51 † |
| Qwen3.5-9B | 56.30 | 88.35 | 68.77 | 44.69 | 88.99 | 59.50 † | 22.05 | 50.27 | 30.65 † | 15.77 | 19.85 | 17.58 |
| Qwen3.6-27B | 58.38 | 70.28 | 63.78 | 43.73 | 52.73 | 47.81 | 23.33 | 45.78 | 30.91 † | 23.80 | 15.30 | 18.63 |
| Gemma-4-12B | 58.10 | 66.76 | 62.13 | 42.50 | 88.89 | 57.50 † | 22.24 | 48.47 | 30.49 † | 23.35 | 15.48 | 18.62 † |
| CWE Type ( ) | Granite | Qwen3.5 | Qwen3.6 | Gemma |
|---|---|---|---|---|
| Benign / No CWE (6424) | 98.8 | 98.6 | 98.9 | 98.3 |
| CWE-119 (4478) | 97.9 | 97.5 | 97.7 | 97.7 |
| CWE-20 (3388) | 98.1 | 97.8 | 98.0 | 97.8 |
| CWE-399 (2889) | 98.8 | 98.6 | 98.7 | 98.6 |
| CWE-264 (2287) | 98.1 | 98.3 | 98.3 | 98.6 |
| CWE-416 (1559) | 99.0 | 98.8 | 98.8 | 98.3 |
| Model | Role | Params |
|---|---|---|
| Our Probe (4 models, Table III ) | inline, generation-time | 13.41–16.03M |
| CodeBERT [ 30 ] | fine-tuned classifier | 125M |
| GraphCodeBERT [ 31 ] | fine-tuned classifier | 125M |
| Llama Guard 3-8B [ 32 ] | external guard model | 8B |
| Granite Guardian 3.x-8B [ 33 ] | external guard model | 8B |
| WildGuard [ 8 ] | external guard model | 7B |
Software Vulnerability Detection
Software vulnerability detection identifies insecure code, pinpoints weaknesses, and helps developers validate or prevent exploitable bugs.
See all 139 papers