diff --git a/internal/serve/smtp_handler.go b/internal/serve/smtp_handler.go index 40eeca3..3f8000c 100644 --- a/internal/serve/smtp_handler.go +++ b/internal/serve/smtp_handler.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "net/http" + "strings" "time" "msgraphtool/internal/common/logger" @@ -19,6 +20,26 @@ type smtpSendRequest struct { Body string `json:"body,omitempty"` } +func sanitizeEmailSubjectInput(subject string) string { + subject = strings.ReplaceAll(subject, "\r", "") + subject = strings.ReplaceAll(subject, "\n", "") + return strings.TrimSpace(subject) +} + +func sanitizeEmailBodyInput(body string) string { + body = strings.ReplaceAll(body, "\r\n", "\n") + body = strings.ReplaceAll(body, "\r", "\n") + + var b strings.Builder + b.Grow(len(body)) + for _, r := range body { + if r == '\n' || r == '\t' || r >= 0x20 { + b.WriteRune(r) + } + } + return b.String() +} + func (s *Server) handleSMTPSendMail(w http.ResponseWriter, r *http.Request) { if s.smtpBase == nil { writeJSON(w, http.StatusServiceUnavailable, apiResponse{Status: "error", Message: "SMTP not configured (set SMTPHOST and related env vars)"}) @@ -61,8 +82,8 @@ func (s *Server) handleSMTPSendMail(w http.ResponseWriter, r *http.Request) { // Clone base config and overlay request content cfg := *s.smtpBase cfg.To = req.To - cfg.Subject = req.Subject - cfg.Body = req.Body + cfg.Subject = sanitizeEmailSubjectInput(req.Subject) + cfg.Body = sanitizeEmailBodyInput(req.Body) cfg.Action = smtp.ActionSendMail if req.From != "" { cfg.From = req.From