diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..d5e1eaa --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2023-10-12 - Header Injection via Environment Variables +**Vulnerability:** HTTP Response Splitting / Header Injection +**Learning:** `responder.Spec.Validate()` correctly prevents control characters in header values designed by the user. However, when these headers contain environment variable placeholders (`${VAR}`), `responder.Render()` expanded them *after* validation. An attacker could potentially inject arbitrary headers or split the response by manipulating an allowed environment variable to contain `\r\n`. +**Prevention:** Sanitized the expanded environment variable values in `Render()` by stripping `\r` and `\n` characters before adding them to the final response headers. diff --git a/internal/responder/responder.go b/internal/responder/responder.go index 6eaa674..376f096 100644 --- a/internal/responder/responder.go +++ b/internal/responder/responder.go @@ -172,7 +172,10 @@ func (r *Responder) Render() events.Response { s := r.Get() headers := make([]events.Header, len(s.Headers)) for i, h := range s.Headers { - headers[i] = events.Header{Name: h.Name, Value: r.env.Expand(h.Value)} + val := r.env.Expand(h.Value) + val = strings.ReplaceAll(val, "\r", "") + val = strings.ReplaceAll(val, "\n", "") + headers[i] = events.Header{Name: h.Name, Value: val} } return events.Response{ Status: s.Status,