Fix unbounded lightfuzz queue growth from parameter re-discovery loop - #3405
Open
liquidsec wants to merge 3 commits into
Open
Fix unbounded lightfuzz queue growth from parameter re-discovery loop#3405liquidsec wants to merge 3 commits into
liquidsec wants to merge 3 commits into
Conversation
A parameter is identified by its name and type, so the query string of the request that revealed it is context rather than identity. Sites that rotate CSRF tokens or honeypot parameter names on every page load made each observation unique, so dedup never fired and lightfuzz's queue grew without bound. Scans that set url_querystring_collapse=False still treat sibling values as significant, normalized so ordering does not matter.
Every baseline response lightfuzz emits is mined by excavate, which hands the parameters it finds back to lightfuzz. Stop emitting past max_baseline_generations (default 10) so the cycle is bounded even where dedup cannot collapse it.
Contributor
📊 Performance Benchmark Report
📈 Detailed Results (All Benchmarks)
🎯 Performance Summary! 1 regression ⚠️
30 unchanged ✅🔍 Significant Changes (>10%)
🐍 Python Version 3.11.16 |
liquidsec
added a commit
that referenced
this pull request
Aug 27, 2026
Servers that append a session id to the path on every redirect emit an unbounded supply of URLs that dedup treats as distinct. Ingress now drops them past url_max_path_param_repeats (default 10). Only ";key=value" path parameters count; ordinary path segments do not, since a deep path that repeats a directory name is finite and depth is bounded by web_spider_depth.
liquidsec
force-pushed
the
lightfuzz-queue-amplification
branch
from
August 27, 2026 18:36
33e4960 to
7029c11
Compare
liquidsec
added a commit
that referenced
this pull request
Aug 27, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #3405 +/- ##
======================================
+ Coverage 90% 90% +1%
======================================
Files 454 454
Lines 47081 47229 +148
======================================
+ Hits 42320 42479 +159
+ Misses 4761 4750 -11 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Problem
lightfuzz emits a baseline
HTTP_RESPONSEfor each parameter it probes. excavate mines those responses and emits the parameters it finds, which come back to lightfuzz, which probes them and emits more baselines. The loop only terminates if dedup collapses the repeats.WEB_PARAMETER._data_idkeyed on the full URL including its query string. On pages that vary their form on every load (rotating CSRF tokens, randomly named honeypot fields), each generation produced a unique key, so dedup never fired and lightfuzz's incoming queue grew without bound.The same failure happens when the varying part is in the path rather than the query string, for example a session id appended to the path on every redirect.
Changes
Three independent fixes, one per commit.
1. Dedupe
WEB_PARAMETERon the page, not the full URL. A parameter is identified by its name and type, both already separate fields in the dedup key, so the query string of whichever request revealed it is context rather than identity. This also makes POSTPARAM and COOKIE consistent with GETPARAM, whose query string excavate already strips.url_querystring_collapse: Falsestill opts back in to treating sibling parameter values as significant, solightfuzz-maxandlightfuzz-xsskeep fuzzing each variant separately. Those keys are now normalized, so parameter ordering no longer affects dedup.2. Cap lightfuzz baseline response generations. New
max_baseline_generations(default 10). lightfuzz stops emitting baseline responses once a parameter is that many lightfuzz generations deep, starving excavate of new material. Applied at emit time rather than infilter_event, which runs after dequeue and so would not have prevented the queue from growing.This is what bounds the loop where dedup cannot, which is the
url_querystring_collapse: Falsecase above. Legitimate post-submit discovery runs a few generations deep, so 10 leaves ample headroom.3. Reject URLs whose path repeats a path parameter. New
url_max_path_param_repeats(default 10), enforced at ingress via the existingblacklistedtag so the event never reaches a module queue. The rule is structural, keyed on repetition rather than a list of known session parameter names.Only
;key=valuepath parameters count. Ordinary path segments deliberately do not: a deep path that repeats a directory name is finite, and depth is already bounded byweb_spider_depth. Set to 0 to disable.