A narrow input exposed a missing boundary check.
Nuclei accepts raw HTTP request templates and parses their header and body sections before execution. Issue #7524 documented that a request body consisting of a single line-feed byte could cause both ParseRawRequest and ParseRawRequestWithURL to panic.
The failure was deterministic, small enough to reproduce without load, and localized to body normalization. Zain Nadeem authored the public issue and the merged patch in PR #7525.
The parser removed the only byte, then indexed the result.
The affected code normalized line endings at the end of a raw request body. For ordinary input, inspecting the last byte is safe because bytes remain after normalization. A body containing only \n is different: removing that trailing line feed leaves an empty slice.
Because the same normalization logic appeared in two public parser entry points, a complete correction had to cover both paths. Fixing only one function would have left the equivalent input failure reachable through the other API.
Reduce the input and follow each slice-length transition.
The useful reproduction was not a complex request. It was the smallest body that changes length during normalization: one line-feed character. Comparing that input with an empty body, a CRLF-only body, and a non-empty body ending in LF separated three questions:
- Does the parser handle a body that begins empty?
- Does trimming one newline make a previously non-empty body empty?
- Does ordinary content ending in a newline retain its content without a panic?
Tracing those cases through both parser functions identified the shared assumption: code reached a second last-byte check without re-establishing that the slice still contained a byte.
The first guard did not protect the second index operation.
A length check made the initial trailing-byte inspection safe. After the code shortened the slice, however, the earlier check no longer described the current state. The subsequent bin[len(bin)-1] access assumed at least one byte remained.
// Simplified affected shape
if len(body) > 0 && body[len(body)-1] == '\n' {
body = body[:len(body)-1]
}
// body may now be empty
if body[len(body)-1] == '\r' {
body = body[:len(body)-1]
}
This is a common boundary error in destructive normalization: validation performed before a mutation does not automatically make later indexing safe.
Re-check the invariant at every index boundary.
PR #7525 added explicit non-empty checks before the trailing-byte inspections in both parser implementations. The patch did not change how normal request bodies are decoded; it only prevents an index operation when normalization has produced an empty slice.
// Simplified corrected shape
if len(body) > 0 && body[len(body)-1] == '\n' {
body = body[:len(body)-1]
}
if len(body) > 0 && body[len(body)-1] == '\r' {
body = body[:len(body)-1]
}
Keeping the guard next to the access makes the safety condition local and reviewable. Mirroring the change across both entry points also avoids behavior drifting between raw parsing APIs.
Test the boundary on both sides of the mutation.
The merged change added table-driven coverage that passed four body shapes through both parser functions. The assertions checked that parsing did not panic, returned no error, and produced the expected body.
| Input | Purpose | Expected result |
|---|---|---|
"\n" | Original failing boundary | No panic; empty normalized body |
"\r\n" | Two-byte line ending | No panic; empty normalized body |
"" | Already empty input | No panic; empty body |
"A\n" | Non-empty body with trailing LF | No panic; content retained |
This matrix protects the original failure and the adjacent edge cases most likely to regress if the normalization logic changes later.
The report and authored patch form one verified contribution.
Issue #7524 was opened by Zain Nadeem with the minimal reproduction and root-cause location. PR #7525, also authored by Zain, implemented the guards and regression tests. The PR was merged on 17 July 2026 as commit 0888e6244d1769d562a1f6910e61ff58e68efddf.
The portfolio therefore presents the merged PR as the primary contribution and the issue as its investigation record. It does not substitute the closed issue for a merged patch or attribute a maintainer-authored remediation to Zain.
Mutation invalidates assumptions about collection length.
- Place bounds checks immediately beside index operations when an earlier step can shrink the collection.
- When duplicate parser entry points implement the same normalization, audit and test both rather than assuming one route represents all callers.
- Use the smallest boundary input to expose state transitions; a one-byte case made the empty-slice transition obvious.
- Regression matrices should include the exact failure, an already-empty input, the related CRLF form, and a normal non-empty control.