#145·hetty

nil pointer dereference panic in CancelRequest / ModifyRequest

Author: MS-0x404Created May 3, 2026Updated May 3, 2026

Affected file: pkg/proxy/intercept/intercept.go

Description

CancelRequest calls ModifyRequest with a nil pointer as the modReq argument. Inside ModifyRequest, the code immediately dereferences that pointer before any nil check, causing a guaranteed runtime panic whenever a user cancels an intercepted request.

Steps to reproduce

  1. Enable request interception in Hetty.
  2. Trigger any proxied HTTP request so that it appears in the intercept queue.
  3. Click Cancel on the intercepted request in the admin UI.
  4. The server panics with runtime error: invalid memory address or nil pointer dereference.

Root cause

CancelRequest is designed to send nil through the request channel as an abort signal, but it does so by routing through ModifyRequest, which unconditionally dereferences the pointer first:

go
// CancelRequest passes nil as modReq:
func (svc *Service) CancelRequest(reqID ulid.ULID) error {
    return svc.ModifyRequest(reqID, nil, nil) // nil passed here
}

// ModifyRequest immediately dereferences it — PANIC:
func (svc *Service) ModifyRequest(reqID ulid.ULID, modReq *http.Request, modifyResponse *bool) error {
    // ...
    *modReq = *modReq.WithContext(req.req.Context()) // nil dereference
}

Note that ClearRequests correctly sends nil directly to the channel without going through ModifyRequest, showing the intended pattern was known but not applied consistently.

Suggested fix

Add a nil guard in ModifyRequest before dereferencing the pointer:

go
if modReq != nil {
    *modReq = *modReq.WithContext(req.req.Context())
    if modifyResponse != nil {
        *modReq = *modReq.WithContext(WithInterceptResponse(modReq.Context(), *modifyResponse))
    }
}

Alternatively, CancelRequest could bypass ModifyRequest entirely and send nil directly to the channel, as ClearRequests already does.