Skip to content

Conversation

@dwisiswant0
Copy link
Member

Changes

fix(httputil): prevent memory corruption in ResponseChain

string accessors.

Replaces unsafe zero-copy conversion.String()
with bytes.Buffer.String() in HeadersString()
and BodyString() methods.

The previous (>= v0.7.0) implementation used
conversion.String() on the buffer's byte slice,
which created a string that shared memory with the
pooled bytes.Buffer. When buffers were returned
to the pool (via Close()) and reused, the
strings held by consumers would be corrupted lmao.

Proof

patch:

$ go test -v -race -run "^TestResponseChain_StringSafety$" ./http/
=== RUN   TestResponseChain_StringSafety
--- PASS: TestResponseChain_StringSafety (0.00s)
PASS
ok  	github.com/projectdiscovery/utils/http	1.043s

main:

$ git cherry-pick b09f27a
$ go test -v -race -run "^TestResponseChain_StringSafety$" ./http/
=== RUN   TestResponseChain_StringSafety
    respChain_test.go:1228: 
        	Error Trace:	/home/dw1/Development/PD/utils/http/respChain_test.go:1228
        	Error:      	"ALERTA_GARBAGE_DATA_OVERWRITING_MEMORY_ALERTA_GARBAGE_DATA_OVERWRITING_MEMOR" does not contain "Original Header Value"
        	Test:       	TestResponseChain_StringSafety
        	Messages:   	HeadersString() content changed after buffer reuse - unsafe memory sharing detected
--- FAIL: TestResponseChain_StringSafety (0.00s)
FAIL
FAIL	github.com/projectdiscovery/utils/http	0.034s
FAIL

string accessors.

Replaces unsafe zero-copy `conversion.String()`
with `bytes.Buffer.String()` in `HeadersString()`
and `BodyString()` methods.

The previous (>= v0.7.0) implementation used
`conversion.String()` on the buffer's byte slice,
which created a string that shared memory with the
pooled `bytes.Buffer`. When buffers were returned
to the pool (via `Close()`) and reused, the
strings held by consumers would be corrupted lmao.

Signed-off-by: Dwi Siswanto <[email protected]>
Comment on lines 317 to 321
// FullResponseString returns the current response as string in the chain.
//
// The returned string is a copy and remains valid even after Close() is called.
// This is a zero-copy operation from the byte slice.
func (r *ResponseChain) FullResponseString() string {
return conversion.String(r.FullResponseBytes())
Copy link
Member Author

Choose a reason for hiding this comment

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

FullResponseString() is already safe because FullResponseBytes() returns a new slice, so I will leave it as is to maintain the zero-copy optimization on that specific method (avoiding a second copy).

@Mzack9999 Mzack9999 merged commit 6ddbc26 into main Nov 30, 2025
7 checks passed
@Mzack9999 Mzack9999 deleted the dwisiswant0/fix/httputil/prevent-memory-corruption-in-ResponseChain branch November 30, 2025 09:05
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.

httputil: data corruption in ResponseChain string accessors

3 participants