Skip to content

Fix safe-prefix cache boundary bypass - #87

Merged
chiruu12 merged 1 commit into
devfrom
fix/safe-prefix-cache-overlap
Jul 20, 2026
Merged

Fix safe-prefix cache boundary bypass#87
chiruu12 merged 1 commit into
devfrom
fix/safe-prefix-cache-overlap

Conversation

@chiruu12

Copy link
Copy Markdown
Collaborator

Summary

  • Re-scan a configurable overlap window at the safe-prefix boundary (aligned with StreamScanner, default 256 chars) so split injection phrases cannot bypass detection
  • Scope chunk/prefix cache keys by source + policy/scanner fingerprint so USER ALLOW is not reused for RETRIEVED (or other policy)
  • Add regression coverage for the audit PoC (Please ignore pre → full phrase must BLOCK with cache on)

Fixes#82
Fixes#83

Test plan

  • make check from sdk/
  • make test-cov from sdk/
  • CI green on this PR

@greptile-apps

Copy link
Copy Markdown

Greptile Summary

This PR tightens cache handling around safe-prefix scans. The main changes are:

  • Adds overlap rescanning at cached safe-prefix boundaries.
  • Scopes prefix and chunk cache keys by source and policy fingerprint.
  • Reuses the same overlap helper in streaming scans.
  • Adds tests for split injection phrases and source-separated cache entries.

Confidence Score: 4/5

The cache path needs a fingerprint fix before merging.

  • Cached results can be reused after scan-affecting policy or scanner settings change.
  • The default boundary-overlap behavior is covered by tests and looks consistent with the streaming path.
  • The import and re-export changes do not show a module-loading problem.

sdk/src/unplug/guard.py

Security Review

The default overlap path improves protection against split prompt-injection phrases. The remaining security concern is stale cached safety decisions when scan-affecting policy or scanner settings change without changing the cache fingerprint.

Important Files Changed

FilenameOverview
sdk/src/unplug/guard.pyAdds cache fingerprinting and overlap-aware suffix scans; the fingerprint misses several settings that can change scan output.
sdk/src/unplug/core/runtime/cache.pyAdds scoped cache keys, chunk-key helpers, and the overlap skip helper.
sdk/src/unplug/config/cache.pyAdds configurable prefix overlap with a default matching streaming, while allowing zero to disable the protection window.
sdk/src/unplug/streaming.pySwitches streaming overlap logic to the shared runtime cache helper.
sdk/src/unplug/api/cache.pyRe-exports the new cache helpers and default overlap constant.
sdk/tests/unit/core/runtime/test_cache.pyAdds tests for source-separated cache keys and default boundary-overlap behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[scan_request with cache enabled] --> B[Build cache key parts]
B --> C[doc/text hash + source + policy fingerprint]
C --> D{chunk cache hit?}
D -- yes --> E[Return cached result]
D -- no --> F{safe prefix verifies?}
F -- yes --> G[Scan from prefix minus overlap]
F -- no --> H[Scan full text]
G --> I[Merge suffix offsets]
H --> J[Use full scan result]
I --> K{advance safe prefix?}
J --> K
K --> L[Store prefix and chunk result]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[scan_request with cache enabled] --> B[Build cache key parts]
B --> C[doc/text hash + source + policy fingerprint]
C --> D{chunk cache hit?}
D -- yes --> E[Return cached result]
D -- no --> F{safe prefix verifies?}
F -- yes --> G[Scan from prefix minus overlap]
F -- no --> H[Scan full text]
G --> I[Merge suffix offsets]
H --> J[Use full scan result]
I --> K{advance safe prefix?}
J --> K
K --> L[Store prefix and chunk result]
Loading

Fix All in Claude Code

Reviews (1): Last reviewed commit: "Fix safe-prefix cache boundary bypass" | Re-trigger Greptile

Comment threadsdk/src/unplug/guard.py
Comment threadsdk/src/unplug/config/cache.py
@github-actions

Copy link
Copy Markdown

coverage

SDK Coverage •
FileStmtsMissCoverMissing
src/unplug
guard.py3512493%132, 199–200, 202, 218–219, 293, 306, 309, 314, 422, 455, 457, 558, 563, 598, 730–731, 733–736, 742, 761
streaming.py61690%52, 57, 63–64, 92, 109
src/unplug/core/runtime
cache.py88594%30, 32, 119, 150, 181
TOTAL721289687%

TestsSkippedFailuresErrorsTime
119325 💤0 ❌0 🔥39.911s ⏱️

@chiruu12
chiruu12 merged commit 4b18d11 into devJul 20, 2026
6 checks passed
@chiruu12
chiruu12 deleted the fix/safe-prefix-cache-overlap branch July 20, 2026 13:33
This was referenced Jul 20, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[security] Chunk/prefix cache keys ignore source and policy [security] Safe-prefix cache skips injection spanning the prefix boundary

1 participant

@chiruu12