Skip to content

fix: avoid panic in BuildRequest when request response has no request - #7601

Merged
Mzack9999 merged 1 commit into
projectdiscovery:devfrom
DPS0340:fix/buildrequest-nil-request
Jul 26, 2026
Merged

fix: avoid panic in BuildRequest when request response has no request#7601
Mzack9999 merged 1 commit into
projectdiscovery:devfrom
DPS0340:fix/buildrequest-nil-request

Conversation

@DPS0340

@DPS0340 DPS0340 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Fixes #7600.

What was wrong

RequestResponse.BuildRequest() dereferenced rr.Request unconditionally and panicked when it was absent:

panic: runtime error: invalid memory address or nil pointer dereference

Request is optional — UnmarshalJSON only sets it when a "request" key is present:

reqBin, ok := m["request"]
if ok { ... rr.Request = &req }

So an entry with only a url unmarshals cleanly and then panics on use. The repo's existing TestUnmarshalJSON already covers that exact shape ({"url": "example.com"}), so the state was reachable from code already under test.

Reachability, verified rather than assumed — through the public MetaInput API, which is JSON round-tripped:

ReqResp==nil? false   ReqResp.Request==nil? true
Clone         ok
BuildRequest  PANIC: runtime error: invalid memory address or nil pointer dereference

pkg/protocols/http/request_fuzz.go:61 reaches it after checking only ReqResp != nil, not .Request.

The fix

An early nil check that sets reqErr, matching how the function already reports its other failure:

if rr.Request == nil {
    rr.reqErr = fmt.Errorf("could not create request: no request in request response")
    return
}

This follows the convention already used on the same field elsewhere in the file — Clone() and ID() both guard with if rr.Request != nil. BuildRequest was the odd one out. No new error type, no behaviour change for well-formed input.

Placing it inside the existing sync.Once keeps the error cached like the other path, so repeat calls stay consistent.

Tests

test asserts
TestBuildRequestWithoutRequest unmarshals {"url": ...}, confirms Request is nil, then require.NotPanics + returns an error and a nil request
TestBuildRequestWithRequestStillWorks a parsed raw request still builds, method preserved

The second is the guard rail: a "fix" that simply refused to build anything would pass the first test and fail this one.

Bite-proofed — reverting only http.go makes TestBuildRequestWithoutRequest fail with the original nil-pointer panic.

Verification

go test ./pkg/input/... ./pkg/protocols/common/contextargs/... — all packages ok. gofmt clean. Two files, +39 lines, no behaviour change for valid input.

Summary by CodeRabbit

  • Bug Fixes
    • Prevented crashes when request data is missing by returning a clear error during request building.
    • Kept existing behavior intact for valid inputs, including correct HTTP method handling when a request is provided.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 73c54cd7-3120-4641-a1ac-47d1dbbfc802

📥 Commits

Reviewing files that changed from the base of the PR and between 5bdde4b and 6f5a8ec.

📒 Files selected for processing (2)
  • pkg/input/types/http.go
  • pkg/input/types/http_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/input/types/http_test.go

Walkthrough

BuildRequest now returns a descriptive error when no request is present, avoiding a nil-pointer panic. Tests cover missing-request handling and successful construction with a parsed HTTP request.

Changes

Request construction safety

Layer / File(s) Summary
Guard and regression coverage
pkg/input/types/http.go, pkg/input/types/http_test.go
BuildRequest rejects nil requests with an error; tests verify the nil case and confirm normal request construction remains functional.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: zainnadeem786

Poem

A bunny found a missing request,
And stopped the crash with care;
An error hopped out neatly,
While GET still traveled there.
Tests twitched their whiskers—
Safe paths everywhere!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% 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 clearly and accurately summarizes the main fix: preventing BuildRequest from panicking when Request is missing.
Linked Issues check ✅ Passed The change adds the requested nil check, returns an error instead of panicking, and adds tests covering nil and valid Request cases.
Out of Scope Changes check ✅ Passed The edits are limited to the BuildRequest fix and its tests, with no unrelated or extraneous changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@DPS0340

DPS0340 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

One scope clarification, so this is judged on what it actually fixes.

I tried to reach the panic through the CLI and could not: the jsonl/burp input formats build their RequestResponse via ParseRawRequestWithURL, which always populates Request. I verified that against the built binary — -im jsonl with a {"url": "..."}-only line runs cleanly, including through the fuzzing path.

Where it is reachable is the library/SDK surface, which is what this PR targets:

  • RequestResponse.UnmarshalJSON deliberately treats request as optional (if ok), so any caller deserialising a RequestResponse — or a MetaInput via MetaInput.Unmarshal, which is JSON round-tripped — can hold one with Request == nil.
  • pkg/protocols/http/request_fuzz.go:61 then calls BuildRequest() after checking only ReqResp != nil.

So this is a robustness fix for embedders rather than a live CLI crash. I'd rather say that plainly than overstate it.

The supporting argument for it being an oversight stands either way: Clone() and ID() both guard the same field with if rr.Request != nil, and I probed every exported method on the type — Clone, ID, MarshalJSON all handle the nil case; BuildRequest was the only one that panicked.

Happy to close this if you consider the nil state out of contract for the exported API.

@DPS0340
DPS0340 force-pushed the fix/buildrequest-nil-request branch from 5bdde4b to 6f5a8ec Compare July 26, 2026 08:17
@Mzack9999
Mzack9999 merged commit eb1bb88 into projectdiscovery:dev Jul 26, 2026
19 checks passed
Sign up for free to 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.

[BUG] BuildRequest() panics on a RequestResponse without a request

2 participants