fix: audit round 4 — XSS in HTML report export, SSRF webhook guard, body limit
CI / go test + web typecheck (push) Canceled after 0s
CI / build + deploy (Nix) — flowsight (push) Canceled after 0s

- ToHTML() now html.EscapeString on ticker, generated_at, section name/body, citations (stored/LLM content can't inject script into exported file)
- Discord destination webhook_url restricted to discord.com/discordapp.com hosts (SSRF guard: server POSTs alert cards; no private IPs or arbitrary hosts)
- Router middleware caps POST/PUT/PATCH bodies at 1 MiB (MaxBytesReader)
- TestDestinations updated: non-discord host must 422, uses realistic discord.com webhook URL
This commit is contained in:
asepharyana
2026-09-16 14:43:56 +07:00
parent b19b9c71d1
commit 05a3bc7471
4 changed files with 53 additions and 9 deletions
+10
View File
@@ -63,6 +63,16 @@ func New(cfg config.Config, db *store.DB, cache *store.Cache, s *sectors.Client)
func (s *Server) Router() http.Handler {
r := chi.NewRouter()
r.Use(middleware.Logger, middleware.Recoverer, middleware.Heartbeat("/ping"))
// Cap request bodies (1 MiB) so large POSTs cannot exhaust memory.
// JSON bodies here are tiny (auth, screen filters, chat prompts).
r.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if req.Body != nil && (req.Method == http.MethodPost || req.Method == http.MethodPut || req.Method == http.MethodPatch) {
req.Body = http.MaxBytesReader(w, req.Body, 1<<20)
}
next.ServeHTTP(w, req)
})
})
r.Route("/api", func(r chi.Router) {
r.Get("/health", s.Health)
r.Get("/auth/start", s.AuthStart)