Skip to content

fix: honor -rl (global rate limit) when -rls is not set#1753

Closed
Rhan2020 wants to merge 2 commits intoprojectdiscovery:devfrom
Rhan2020:fix/rl-rls-1434
Closed

fix: honor -rl (global rate limit) when -rls is not set#1753
Rhan2020 wants to merge 2 commits intoprojectdiscovery:devfrom
Rhan2020:fix/rl-rls-1434

Conversation

@Rhan2020
Copy link

@Rhan2020 Rhan2020 commented Feb 26, 2026

Fixes #1434.

The global rate limit flag (-rl) was effectively ignored for sources that don't have an explicit per-source entry in -rls, causing subfinder to run unthrottled unless -rls was provided.

Changes:

  • Apply -rl to every source by default.
  • If -rls contains an entry for a source, it overrides the global value.
  • Guard against nil custom rate limit configuration.
  • Clamp negative -rl values to 0.

Tests:

  • Add coverage for nil custom rate limit (no panic) and negative global rate limit.

/claim #1434

Summary by CodeRabbit

  • New Features

    • Per-source rate limits now inherit a computed global default; per-source overrides continue to be supported.
  • Bug Fixes

    • Negative global rate limits are clamped to zero; global default is applied only when positive.
  • Tests

    • Added unit tests validating global-default and per-source override behavior across edge cases.

Ensure global -rl applies to all sources by default, even when -rls is not provided. Also guard against nil custom rate limit and clamp negative global rate limits to zero.

Adds tests for nil custom rate limit and negative global rate limit.
@neo-by-projectdiscovery-dev
Copy link

neo-by-projectdiscovery-dev bot commented Feb 26, 2026

Neo - PR Security Review

No security issues found

Highlights

  • Test updated to use math.MaxUint32 for unlimited rate limit testing
  • Rate limiting logic maintains proper input validation and clamping

Comment @neo help for available commands. · Open in Neo

@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f3583a and afd4e7d.

📒 Files selected for processing (2)
  • pkg/passive/passive.go
  • pkg/passive/passive_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/passive/passive_test.go
  • pkg/passive/passive.go

Walkthrough

Defaulting for per-source rate limits in the passive package was changed: per-source limits now start from a computed global value (non-zero only when globalRateLimit > 0) and are overridden only when a CustomRateLimit is provided. Tests were added to validate various global and per-source scenarios.

Changes

Cohort / File(s) Summary
Rate Limit Initialization Logic
pkg/passive/passive.go
Adjusted defaulting so per-source rl is initialized from a computed global value (non-zero only if globalRateLimit > 0) and per-source CustomRateLimit overrides are applied via a unified defaulting function; globalRateLimit <= 0 yields zero default.
Rate Limiter Test Suite
pkg/passive/passive_test.go
Added TestBuildMultiRateLimiter with cases for nil custom map, applying global when source absent, clamping negative global to zero, and an effectively unlimited global (math.MaxInt32); asserts no errors and non-nil limiter.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I hopped through configs, small and bright,

Folded globals into per-source light.
Overrides now politely say when to bend,
Tests ensure the hopping has a proper end.
🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: ensuring the global rate limit flag (-rl) is honored when per-source limits (-rls) are not set, which directly addresses the changeset's primary objective.
Linked Issues check ✅ Passed The code changes directly address issue #1434's requirements: global -rl now applies to sources without per-source overrides, per-source -rls entries override the global value, nil custom rate limit is guarded, and negative values are clamped to zero.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing rate limit behavior in the passive package: modifications to default logic in passive.go and test coverage additions in passive_test.go are directly related to issue #1434.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
pkg/passive/passive_test.go (1)

25-35: Tests verify success but not actual behavior.

The test confirms the function doesn't error with a global rate limit of 3 and a custom entry for "crtsh" only, but it doesn't verify that "hackertarget" actually received the global limit of 3. Consider adding assertions on the returned MultiLimiter state if the API allows inspection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/passive/passive_test.go` around lines 25 - 35, The test only checks no
error from agent.buildMultiRateLimiter but doesn't verify that the non-custom
source "hackertarget" received the global limit; update the test to assert the
returned MultiLimiter state for "hackertarget" equals the global limit (3) by
inspecting whatever accessor exists on the returned value (e.g., a
Get/LimitFor(source) method or an exported map inside the MultiLimiter), and if
no inspector exists add a small test-only accessor on MultiLimiter (or expose
its internal map) so the test can assert limiter value for "hackertarget";
reference New, buildMultiRateLimiter, customRL, and MultiLimiter when locating
code to change.
pkg/passive/passive.go (2)

89-92: Consider checking before converting for clarity.

When globalRateLimit is negative, uint(globalRateLimit) produces a large wrapped value before line 91 corrects it. The code is functionally correct, but checking first is more readable.

Cleaner ordering
-	global := uint(globalRateLimit)
-	if globalRateLimit < 0 {
-		global = 0
+	var global uint
+	if globalRateLimit > 0 {
+		global = uint(globalRateLimit)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/passive/passive.go` around lines 89 - 92, Replace the current
conversion-first pattern by checking globalRateLimit before casting: instead of
doing global := uint(globalRateLimit) and then correcting when globalRateLimit <
0, branch on globalRateLimit and assign global = 0 for negatives, otherwise set
global = uint(globalRateLimit); refer to the variables globalRateLimit and
global in passive.go to locate the change.

116-121: Note: Explicit per-source 0 cannot override to unlimited when a global limit is set.

If a user sets -rls source=0 intending to make that source unlimited while -rl is non-zero, sourceRateLimitOrDefault returns the global default instead. This may be intentional (0 means "inherit default"), but worth documenting if users expect explicit 0 to mean "unlimited for this source."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/passive/passive.go` around lines 116 - 121, The helper
sourceRateLimitOrDefault currently treats sourceRateLimit==0 as "use default"
which prevents an explicit per-source 0 from meaning unlimited; change the logic
in sourceRateLimitOrDefault to return sourceRateLimit when it is explicitly
provided (including 0) and only fall back to defaultRateLimit when
sourceRateLimit is some sentinel like an unset value (e.g., use a pointer or a
separate boolean flag) or, simpler, document the behavior and rename the
function to make semantics clear; update callers of sourceRateLimitOrDefault and
any user docs/comments so that a sourceRateLimit of 0 is either explicitly
defined as unlimited or clearly documented as "inherit default."
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/passive/passive_test.go`:
- Around line 48-54: The test "UnlimitedGlobalRateLimitBehavesLikeUnlimited" is
misleading because it passes math.MaxInt32 which does not hit the unlimited
branch (addRateLimiter checks for math.MaxUint32); update the test to pass
math.MaxUint32 (or change the test name to reflect a very large limit) so it
actually exercises the unlimited code path in
buildMultiRateLimiter/addRateLimiter — ensure any parameter types are adjusted
to accept the uint value if necessary and keep assertions the same
(require.NoError, require.NotNil) after the change.

---

Nitpick comments:
In `@pkg/passive/passive_test.go`:
- Around line 25-35: The test only checks no error from
agent.buildMultiRateLimiter but doesn't verify that the non-custom source
"hackertarget" received the global limit; update the test to assert the returned
MultiLimiter state for "hackertarget" equals the global limit (3) by inspecting
whatever accessor exists on the returned value (e.g., a Get/LimitFor(source)
method or an exported map inside the MultiLimiter), and if no inspector exists
add a small test-only accessor on MultiLimiter (or expose its internal map) so
the test can assert limiter value for "hackertarget"; reference New,
buildMultiRateLimiter, customRL, and MultiLimiter when locating code to change.

In `@pkg/passive/passive.go`:
- Around line 89-92: Replace the current conversion-first pattern by checking
globalRateLimit before casting: instead of doing global := uint(globalRateLimit)
and then correcting when globalRateLimit < 0, branch on globalRateLimit and
assign global = 0 for negatives, otherwise set global = uint(globalRateLimit);
refer to the variables globalRateLimit and global in passive.go to locate the
change.
- Around line 116-121: The helper sourceRateLimitOrDefault currently treats
sourceRateLimit==0 as "use default" which prevents an explicit per-source 0 from
meaning unlimited; change the logic in sourceRateLimitOrDefault to return
sourceRateLimit when it is explicitly provided (including 0) and only fall back
to defaultRateLimit when sourceRateLimit is some sentinel like an unset value
(e.g., use a pointer or a separate boolean flag) or, simpler, document the
behavior and rename the function to make semantics clear; update callers of
sourceRateLimitOrDefault and any user docs/comments so that a sourceRateLimit of
0 is either explicitly defined as unlimited or clearly documented as "inherit
default."

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d4f804 and 3f3583a.

📒 Files selected for processing (2)
  • pkg/passive/passive.go
  • pkg/passive/passive_test.go

@Rhan2020 Rhan2020 closed this by deleting the head repository Feb 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Issue] The rl,rls options are not supported

1 participant