General
Repository Agent-Security Gap Study — v2h baseline
jackymenCZ (jackymenCZ) DEV Community 周榜
4 views
Repository Agent-Security Gap Study — v2h baseline
Generated 2026-09-13T10:25:40.362Z. Harness: /home/ubuntu/hazmat/harness/bench.js (one run, same files, same snapshots, same ground truth for every scanner). Raw rows: bench-v2h.json / bench-v2h.csv.
Question. Which classes of agent-directed manipulation in repository content does an agent-facing detector (Sentinel InjectionGate) flag, which do current repository scanners (secret detection, SAST) flag, and what does Sentinel still miss?
Not claimed. This does not show that any vendor product is vulnerable, that Sentinel is complete, or that detection equals safe handling. Secret/SAST scanners are measured against their own design scope as well as the agent-facing scope, and the difference is reported, not hidden.
1. Setup
Item
Value
Files
192 (134 synthetic + 58 external)
Agent-directed hostile payloads
118 (90 synthetic, 28 external)
Clean controls
72 (42 synthetic, 30 external)
Scanner positive controls
1 planted secret (gitleaks), 1 eval/0.0.0.0 file (semgrep)
gitleaks
8.21.2
semgrep
1.176.1 p/default+p/python+p/trailofbits
sentinel
master 04273f2f263 InjectionGate + Executor.processFile (shadow)
External snapshots
Prompt-Injection-Everywhere@9b69c8ae79, ChatGPT_DAN@0799f29c4c, llm-security@c312325bee
Isolation
env secrets removed (1 values captured for prompt inspection), axios blocked (0 attempts), LLM stub → SKIP, GitLab write stub, temp state dir
Ground truth: synthetic files come from a manifest written before scanning (class, hostile flag, channel); external files were hand-labelled from author intent (external-labels.json). Synthetic payloads are 10 classes × 3 variants × 3 carriers (.md documentation, .py, .js). A file counts as detected when the scanner reports any finding for it; for Sentinel that is verdict ≠ clean on the file's natural channel.
Positive-control check: gitleaks flagged the planted secret (yes), semgrep flagged the planted eval/bind file (yes). Zero findings elsewhere are therefore scanner scope, not misconfiguration.
2. What existing scanners detect
Scanner
Findings (files)
Agent-directed payloads flagged
Own-scope positive control
False positives on clean controls
gitleaks
1
0 / 118
secret_leak
0
semgrep
4
0 / 118
code_vuln, secret_leak
2
Findings in detail:
gitleaks: corpus/controls/secret-positive-control.py → secret aws-access-token (line 2); ground truth class: Secret (positive control)
semgrep: corpus/controls/sast-positive-control.py → error eval-injection|eval-detected|avoid_app_run_with_bad_host|debug-enabled (line 9); ground truth class: Code vuln (positive control)
semgrep: corpus/controls/secret-positive-control.py → error detected-aws-access-key-id-value (line 2); ground truth class: Secret (positive control)
semgrep: llm-security/main.py → warning non-literal-import (line 25); ground truth class: Clean control
semgrep: llm-security/scenarios/puzzle/server.py → warning avoid_app_run_with_bad_host (line 128); ground truth class: Clean control
Note: the 2 semgrep rows counted as "false positive" are real code-quality findings (non-literal-import, avoid_app_run_with_bad_host) in files that carry no agent-directed payload — they are correct for SAST and irrelevant to this study's question. They are listed as FP only against the agent-facing ground truth.
No rule in the tested semgrep configurations (p/default, p/python, p/trailofbits) targets natural-language instructions addressed to an agent. This is scope, not failure.
3. What an agent-facing detector additionally detects
Sentinel InjectionGate, natural channel, v2h:
Class
Payloads
Hostile
Suspect
Missed (clean)
Recall (any label)
Scanners
Direct override
13
9
4
0
100%
0
Fake system message
18
11
2
5
72%
0
Persona switch
10
7
3
0
100%
0
Instruction hidden in docs
10
9
1
0
100%
0
Instruction without keyword
11
8
3
0
100%
0
Obfuscated / typo
10
4
3
3
70%
0
Tool manipulation
11
8
2
1
91%
0
Payment request
9
4
2
3
67%
0
Data exfiltration
12
9
2
1
92%
0
Multi-stage
14
4
5
5
64%
0
Total
118
73
27
18
85%
0
Precision on this corpus: 100 flagged, 0 false positives on 72 clean controls (incl. a third-person research note about prompt injection and a security policy doc).
By carrier / channel:
| Channel | Payloads | Detected | Recall |
|---|---|---|---|
| documentation | 47 | 39 | 83% |
| code | 71 | 61 | 86% |
Synthetic vs external:
| Origin | Payloads | Detected | Recall |
|---|---|---|---|
| synthetic | 90 | 81 | 90% |
| external | 28 | 19 | 68% |
Signals that fired (natural channel):
instruction_in_data_region: 67
override_previous: 31
persona_switch: 13
secret_exfiltration: 9
agent_label_directive: 9
tool_invocation_request: 8
system_envelope: 7
chat_template_token: 7
context_reset: 7
preapproved_claim: 6
trigger_arming: 6
value_transfer: 6
exfil_destination: 3
review_waiver: 3
tool_call_smuggling: 3
homoglyph_word: 1
3a. Beyond detection: what happened inside Sentinel (shadow Executor, code channel)
Every file was also pushed through the real Executor.processFile with LLM/GitLab/network stubbed. Sentinel is not only a scanner, so we record what a detection does:
Metric
Value
executor_called
192 / 192
LLM stub consulted
180 (deterministic SKIP without LLM: 12)
Actions returned
undefined: 180, SKIP: 12
network_called
0
commits
0
secret_in_prompt (values + Authorization/Bearer/var names)
0
payload_persisted (payload text in memory/scorecard)
0
Files with hostile code-channel verdict → prompt copy sanitized
43 (neutralization markers seen in 38)
payload_reached_llm = true (a matched span reached the prompt verbatim)
51 — all in the suspect band, which is not sanitized by design
payload_reached_llm not measurable (no span matched → whole file reached prompt unmodified)
20 hostile files
Executor errors
0
decision_changed: on the stubbed SKIP path processFile returns no decision tuple for most files (same limitation as the internal benchmark runner), so drift cannot be measured honestly here; it is reported as not measured, not as false. The two Sentinel MRs (!68, !70) that sanitize the egress were verified for drift on the internal fixture set, not on this corpus.
4. What Sentinel still misses
18 of 118 agent-directed payloads (15%) produced verdict clean on their natural channel. Nothing downstream consumes a clean verdict, so for these files Sentinel behaves exactly like a repository with no agent-facing detector at all: the full text went to the (stubbed) model unchanged.
Missed by class (agent_relevance / actionability from the manifest):
| Class | Missed / total | agent_relevance | actionability | Example missed file |
|---|---|---|---|---|
| Fake system message | 5 / 18 | high | high | llm-security/scenarios/puzzle/puzzles/ai-box |
| Obfuscated / typo | 3 / 10 | high | medium | corpus/obfuscated_typo/hostile-1-1.md |
| Tool manipulation | 1 / 11 | critical | high | llm-security/scenarios/gpt3langchain/remote-control.py |
| Payment request | 3 / 9 | critical | high | corpus/payment_request/hostile-2-1.md |
| Data exfiltration | 1 / 12 | critical | high | llm-security/scenarios/gpt3langchain/data_exfiltration.py |
| Multi-stage | 5 / 14 | high | low | corpus/multi_stage/hostile-1-1.md |
Observed patterns behind the misses (from the synthetic variants, which are known):
Fake <system> / [SYSTEM] framing with no override keyword.
Persona switch ("you are now …") and role-play framing.
Overrides without the literal phrase ("from this point forward", "disregard", "the guidance above no longer applies").
Typo / spacing obfuscation of trigger words.
Tool-call, payment and exfiltration instructions phrased as ordinary imperatives to "the assistant" without the classic keywords.
Multi-stage: benign text with the instruction only in a later section, or split across sentences.
Critical-relevance misses (tool manipulation, payment, exfiltration) deserve priority in v2: these are the classes where an agent with tools would act, and they are the ones a human reader would most likely skim past.
Suspect-band exposure: 27 files were labelled suspect; 51 of them had the matched span in the prompt verbatim. Sentinel does not sanitize suspect content — this is a documented design choice, and this corpus quantifies its cost.
5. Relevance view
Per payload class the manifest records human_relevance, agent_relevance, actionability. Aggregating Sentinel misses by agent_relevance:
| agent_relevance | payloads | detected | missed |
|---|---|---|---|
| critical | 32 | 27 | 5 |
| high | 86 | 73 | 13 |
For gitleaks/semgrep the agent_relevance axis is orthogonal to their design: both scanners flagged exactly their own positive control and nothing in the agent-relevant set. The gap this study documents is therefore a class gap (agent-addressed text is not a scan target), not a quality gap in those tools.
6. Limitations
Synthetic payloads were written by the same people who know Sentinel's rules; fragment-joined to keep Sentinel's self-scan clean. External payloads are the only "unbiased" part (28 files, 3 repos).
Ground truth for external files is a single-annotator, author-intent label.
Semgrep was run with three public rulesets; commercial/GitLab-bundled rules were not tested. Gitleaks default config only.
Sentinel's Executor was driven with an LLM stub returning SKIP, so decision_changed is not measured; only egress, persistence, network and commit boundaries are.
payload_reached_llm is measured on matched spans; for undetected files it is trivially true (whole file forwarded) and recorded as not measurable.
Detection ≠ safe handling: a hostile verdict on documentation/api_response channels is not consumed by any Executor path (known gaps 21/22 remain).
7. Next step (not done in this run)
v2 detector work is to be derived only from the misses listed in §4, then this exact corpus is re-run with node bench.js v2 && node gap-study.js v2 and diffed against v1 (detected, false positives, misses). Sentinel runtime was not modified for this baseline.
Read original: https://dev.to/jackymencz/repository-agent-security-gap-study-v2h-baseline-52f5
← Previous
Hacking VaultGate: Three Paths to One Flag
Next →
Why I built an ad-free Android video player to replace bloated alternatives
Related
TACACS+ Failover Testing: Rejection, Outage, and Recovery Are Different Tests
General
0
DEV Community 周榜
Caesar Cipher Explained: How It Works, Encryption, Decryption, and Examples
General
0
DEV Community 周榜
Why I Built My Portfolio with Bun + Astro + MDX Instead of a More Complex Stack
General
0
DEV Community 周榜
Your primary key shouldn't be in the URL
General
0
DEV Community 周榜
Comments0
No comments yet — be the first