From d547f96e36fbeec22f75a250932ae94801d0736b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 11 Oct 2026 23:31:47 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20Fi?= =?UTF-8?q?x=20HTTP=20Response=20Splitting=20/=20Header=20Injection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🚨 Severity: HIGH 💡 Vulnerability: Environment variables embedded within user-defined headers could contain Carriage Return Line Feed (`\r\n`) characters. Since variables were expanded *after* headers were validated, a malicious string inside an allowed environment variable could inject arbitrary headers or manipulate the response. 🎯 Impact: An attacker could perform HTTP response splitting or header injection, potentially bypassing CORS, injecting malicious content, or hijacking sessions if portbell is exposed or used in a proxy chain. 🔧 Fix: Added logic in `responder.Render()` to strip `\r` and `\n` characters from expanded environment variables before they are attached to the HTTP response. ✅ Verification: Review the code changes and verify with `make check`. The changes successfully pass all internal tests. Co-authored-by: tejjasdev <213147578+tejjasdev@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ internal/responder/responder.go | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .jules/sentinel.md 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,