Repository navigation
feat(detection): yield the event loop, cap per-request scan time, add semantic-only header opt-out - #132
Merged
Conversation
…t scan time The regex scan awaited only microtasks, so one request's scan held the event loop for its whole duration. It now hands the loop back every ~2 ms of scanning. Add detectionMaxScanSeconds (default 10.0, 0.1 to 60), a per-request cap on the summed regex scan time. Once spent, remaining patterns and values are skipped and a weighted pattern_timeout threat (scan_time_budget_exhausted) is recorded like a per-pattern timeout, so padding a request cannot skip detection.
… a request When a per-pattern timeout or the spent scan budget was what pushed a request over the threshold, the trigger named only the first threat, so the block read as an ordinary pattern match. The trigger now appends the first pattern_timeout threat behind a non-timeout first threat, and a leading timeout reads 'Pattern exceeded scan time budget', matching the reference.
Add excludedSemanticDetectionHeaders (and detectionExclusion({ semanticHeaders })): header names whose values skip the semantic analyzer only, matched case-insensitively and merged between the global and route sets. Regex category scanning of those headers is unchanged. Default empty.
As one value, the semicolons between cookies counted as command separators in the semantic score, so an ordinary logged-in header (a JWT session cookie plus theme and _ga) reached 0.71 and was blocked. Each pair now takes the normal header path and counts against the value budget. Empty pairs are skipped and only spaces around a pair are trimmed, so a CR or LF stays in the scanned value. Ports guard-core #162.
detectionMaxScanSeconds summed the wall time of each pattern, so on a busy or CPU-starved host ordinary requests exceeded the default and failed closed. The budget now records the process CPU time (user plus system) spent in each synchronous scan; a worker-pool scan, whose CPU is not observable from the caller, is charged its wall time. Event loop slicing stays wall based.
rennf93
force-pushed
the
feat/scan-yield-budget-semantic-optout
branch
from
October 15, 2026 06:47
42d30d3 to
0532349
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #131
TypeScript port of Guard-Core/guard-core#167. Scans yield the event loop, a per-request CPU time budget caps total scan time and is named in the trigger when it tips a request, an opt-in semantic-only header exclusion skips only the semantic analyzer, and the Cookie header is scanned one name=value pair at a time.