-
Couldn't load subscription status.
- Fork 978
fix: ensure Host header is set in unsafe mode for rawhttp requests #2297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
WalkthroughA targeted fix synchronizes the Host header in unsafe mode by explicitly setting both Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~5 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
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. Comment |
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
runner/runner.go(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
runner/runner.go (1)
common/customheader/customheader.go (1)
CustomHeaders(10-10)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Test Builds (windows-latest)
- GitHub Check: Test Builds (macOS-latest)
- GitHub Check: release-test
- GitHub Check: Functional Test (windows-latest)
- GitHub Check: Functional Test (ubuntu-latest)
- GitHub Check: Functional Test (macOS-latest)
- GitHub Check: Analyze (go)
runner/runner.go
Outdated
| // Don't override req.Host in unsafe mode if CustomHeaders has Host | ||
| // This allows AutomaticHostHeader(false) to work (see lines 244-251) | ||
| if target.CustomHost != "" { | ||
| req.Host = target.CustomHost | ||
| if scanopts.Unsafe { | ||
| // In unsafe mode, only set req.Host if no Host in CustomHeaders | ||
| if _, hasHost := hp.CustomHeaders["host"]; !hasHost { | ||
| req.Host = target.CustomHost | ||
| } | ||
| } else { | ||
| req.Host = target.CustomHost | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Host header detection logic is incorrect and the fix won't work as intended.
The check at line 1645 uses hp.CustomHeaders["host"] to look for an exact lowercase key "host", but this will always fail because:
- In unsafe mode (lines 201-203): CustomHeaders keys are the entire header string (e.g.,
"Host: example.com"), not just"host" - When parsing raw requests (lines 236-238): Headers are stored with their original casing (e.g.,
"Host"), not lowercase"host"
This means the condition !hasHost will always be true, and req.Host will still be overridden by target.CustomHost, defeating the purpose of this fix.
The correct approach is shown in lines 246-251, which iterates through the keys and checks with case-insensitive prefix matching:
Apply this diff to fix the logic:
// Don't override req.Host in unsafe mode if CustomHeaders has Host
// This allows AutomaticHostHeader(false) to work (see lines 244-251)
if target.CustomHost != "" {
if scanopts.Unsafe {
// In unsafe mode, only set req.Host if no Host in CustomHeaders
- if _, hasHost := hp.CustomHeaders["host"]; !hasHost {
+ hasHostHeader := false
+ for name := range hp.CustomHeaders {
+ nameLower := strings.TrimSpace(strings.ToLower(name))
+ if strings.HasPrefix(nameLower, "host") {
+ hasHostHeader = true
+ break
+ }
+ }
+ if !hasHostHeader {
req.Host = target.CustomHost
}
} else {
req.Host = target.CustomHost
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Don't override req.Host in unsafe mode if CustomHeaders has Host | |
| // This allows AutomaticHostHeader(false) to work (see lines 244-251) | |
| if target.CustomHost != "" { | |
| req.Host = target.CustomHost | |
| if scanopts.Unsafe { | |
| // In unsafe mode, only set req.Host if no Host in CustomHeaders | |
| if _, hasHost := hp.CustomHeaders["host"]; !hasHost { | |
| req.Host = target.CustomHost | |
| } | |
| } else { | |
| req.Host = target.CustomHost | |
| } | |
| } | |
| // Don't override req.Host in unsafe mode if CustomHeaders has Host | |
| // This allows AutomaticHostHeader(false) to work (see lines 244-251) | |
| if target.CustomHost != "" { | |
| if scanopts.Unsafe { | |
| // In unsafe mode, only set req.Host if no Host in CustomHeaders | |
| hasHostHeader := false | |
| for name := range hp.CustomHeaders { | |
| nameLower := strings.TrimSpace(strings.ToLower(name)) | |
| if strings.HasPrefix(nameLower, "host") { | |
| hasHostHeader = true | |
| break | |
| } | |
| } | |
| if !hasHostHeader { | |
| req.Host = target.CustomHost | |
| } | |
| } else { | |
| req.Host = target.CustomHost | |
| } | |
| } |
🤖 Prompt for AI Agents
In runner/runner.go around lines 1640 to 1651, the boolean check using
hp.CustomHeaders["host"] is incorrect because CustomHeaders can contain full
header strings or original-cased keys; replace it with iteration over
hp.CustomHeaders keys and perform a case-insensitive prefix/equality check
(e.g., lowercase key and check if it == "host" or strings.HasPrefix(lowerKey,
"host:")) to detect an existing Host header; only set req.Host =
target.CustomHost in unsafe mode when no such Host header is found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ayanrajpoot10 Thanks for your PR. This function is already performed automatically by the rawhttp library (ref: https://github.com/projectdiscovery/rawhttp/blob/132ebe7ef211155e77497e4432c5cb13dec1ba79/options.go#L31). Did you face any situation in which the action was not performed properly?
In the first screenshot, raw.txt shows Host: de1.wstunnel.xyz, but when the request is made, it changes to arturo.ns.cloudflare.com, which is our target — that’s the issue. In the second screenshot, after making this change, the Host header remains as de1.wstunnel.xyz, which means the issue is resolved. This suggests that there may be something wrong with the rawhttp library. |
|
@Mzack9999 The problem is that |
|
|


fixes #2296
Summary by CodeRabbit