diff --git a/.jules/sentinel.md b/.jules/sentinel.md
new file mode 100644
index 000000000..957633d6c
--- /dev/null
+++ b/.jules/sentinel.md
@@ -0,0 +1,4 @@
+## 2026-06-11 - [XSS in Default Error Handler]
+**Vulnerability:** Reflected Cross-Site Scripting (XSS) in default HTML error response.
+**Learning:** The default error controller generated raw HTML incorporating the unescaped Exception message. In Crystal, `Exception#message` can be `nil` (`String?`), so safely interpolating it into HTML requires `HTML.escape(@ex.message || "")` and explicitly requiring the `"html"` module.
+**Prevention:** Always escape user-controllable or dynamic string data, including exception messages, before interpolating it into an HTML template or string.
diff --git a/spec/amber/pipes/error_spec.cr b/spec/amber/pipes/error_spec.cr
index 6148f531c..66280406a 100644
--- a/spec/amber/pipes/error_spec.cr
+++ b/spec/amber/pipes/error_spec.cr
@@ -25,6 +25,19 @@ module Amber
response.status_code.should eq 500
end
+
+ it "escapes exception messages in the HTML response body" do
+ error = Error.new
+ error.next = ->(_context : HTTP::Server::Context) { raise "" }
+ request = HTTP::Request.new("GET", "/")
+ request.headers["Accept"] = "text/html"
+
+ response = create_request_and_return_io(error, request)
+
+ response.status_code.should eq 500
+ response.body.should contain("<script>alert('xss')</script>")
+ response.body.should_not contain("