Email Injection in Chi
How Email Injection Manifests in Chi
Email injection in Chi applications typically occurs when user input flows directly into email headers or message bodies without proper sanitization. Chi's HTTP middleware stack and template rendering create specific attack vectors that developers must understand.
The most common scenario involves form submissions where the email address, subject, or message body contains newline characters that attackers can exploit. Consider this vulnerable Chi handler:
func sendContactEmail(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
email := r.FormValue("email")
subject := r.FormValue("subject")
message := r.FormValue("message")
// Vulnerable: direct interpolation without sanitization
emailBody := fmt.Sprintf("From: %s <%s>\nSubject: %s\n\n%s", name, email, subject, message)
smtp.SendMail("smtp.example.com:587", smtp.PlainAuth("", "user", "pass", "smtp.example.com"),
"from@example.com", []string{"admin@example.com"}, []byte(emailBody))
}An attacker could submit:
email: "victim@example.com\nCc: attacker@example.com\nBcc: spammer@example.com"
subject: "Hello\nContent-Type: text/html\n\n<img src=\"http://attacker.com/track.gif\">"
This would create additional email headers, potentially sending spam to third parties or injecting HTML content. Chi's default middleware doesn't automatically sanitize these inputs, making it the developer's responsibility.
Another Chi-specific pattern involves using context values for email addresses:
func EmailMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
email := r.Header.Get("X-User-Email")
ctx := context.WithValue(r.Context(), "userEmail", email)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func sendNotification(w http.ResponseWriter, r *http.Request) {
email := r.Context().Value("userEmail").(string)
// No validation of email format or content
sendEmail(email, "Notification", "Your account was updated")
}If the X-User-Email header contains newline characters, it can break the email header structure. Chi's middleware chain passes this context through without validation, creating a potential injection point.
Template rendering in Chi applications can also introduce vulnerabilities. When using Go's html/template package with Chi, developers might incorrectly assume templates handle email injection:
tmpl, err := template.New("email").Parse(`From: {{.From}}\nSubject: {{.Subject}}\n\n{{.Body}}`)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
tmpl.Execute(w, data)
The html/template package escapes HTML but doesn't prevent newline-based header injection, leaving applications vulnerable.
Chi-Specific Detection
Detecting email injection in Chi applications requires both static analysis and runtime scanning. middleBrick's black-box scanning approach is particularly effective for Chi APIs because it tests the actual runtime behavior without requiring source code access.
For Chi applications, middleBrick automatically tests for email injection by submitting payloads with newline characters in email-related parameters. The scanner identifies Chi-specific patterns like:
POST /api/contact HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
email=victim%40example.com%0aCc%3aspammer%40example.com%0aBcc%3aspammer2%40example.com&subject=Test%0aContent-Type%3atext%2fhtml%0a%0a%3cimg%20src%3d%22http%3a%2f%2fattacker.com%2ftrack.gif%22%3e&message=Hello
middleBrick's 12 security checks include Input Validation testing that specifically looks for header injection vulnerabilities. The scanner analyzes the response to determine if the injected headers were processed, which would indicate a successful attack.
For Chi applications using OpenAPI specifications, middleBrick's spec analysis can identify parameters that should be validated for email injection. When you upload your Chi application's OpenAPI spec, middleBrick cross-references the documented parameters with its runtime findings:
$ middlebrick scan https://api.example.com --spec openapi.yaml
Scan Results:
✅ Authentication: A (no auth bypass found)
⚠️ Input Validation: C (email injection vulnerability in /contact POST)
- Severity: High
- Finding: Newline characters in email field could create additional headers
- Remediation: Sanitize inputs, validate email format
middleBrick's LLM/AI Security checks are also relevant for Chi applications using AI features. If your Chi API integrates with language models and accepts user input for prompts, middleBrick tests for prompt injection that could lead to data exfiltration through email channels.
Developers can integrate middleBrick's detection into their Chi development workflow using the CLI or GitHub Action. For example, adding email injection scanning to your CI/CD pipeline:
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run middleBrick Scan
run: |
npm install -g middlebrick
middlebrick scan https://staging.example.com/api --fail-below B
This configuration ensures that any email injection vulnerabilities are caught before deployment to production.
Chi-Specific Remediation
Remediating email injection in Chi applications involves input sanitization, validation, and using secure email libraries. The most effective approach combines multiple defensive layers.
First, implement strict input validation using Go's email validation and sanitization functions:
import (
"net/mail"
"strings"
"regexp"
)
func sanitizeEmailInput(email, subject, message string) (string, string, string, error) {
// Validate email format
if _, err := mail.ParseAddress(email); err != nil {
return "", "", "", fmt.Errorf("invalid email format: %w", err)
}
// Remove newlines and carriage returns
cleanEmail := strings.ReplaceAll(email, "\n", "")
cleanEmail = strings.ReplaceAll(cleanEmail, "\r", "")
cleanSubject := strings.ReplaceAll(subject, "\n", " ")
cleanSubject = strings.ReplaceAll(cleanSubject, "\r", " ")
cleanMessage := strings.ReplaceAll(message, "\n", "\n")
cleanMessage = strings.ReplaceAll(cleanMessage, "\r", "")
// Additional sanitization: remove suspicious header patterns
headerPattern := regexp.MustCompile(`(?i)(content-type|bcc|cc|to|from|subject|reply-to):`)
if headerPattern.MatchString(cleanSubject) || headerPattern.MatchString(cleanMessage) {
return "", "", "", errors.New("message contains suspicious header patterns")
}
return cleanEmail, cleanSubject, cleanMessage, nil
}
func sendSecureEmail(w http.ResponseWriter, r *http.Request) {
email := r.FormValue("email")
subject := r.FormValue("subject")
message := r.FormValue("message")
cleanEmail, cleanSubject, cleanMessage, err := sanitizeEmailInput(email, subject, message)
if err != nil {
http.Error(w, "Invalid input: "+err.Error(), 400)
return
}
// Use structured email construction instead of string interpolation
msg := fmt.Sprintf("From: %s\r\nSubject: %s\r\n\r\n%s",
cleanEmail, cleanSubject, cleanMessage)
err = smtp.SendMail("smtp.example.com:587", smtp.PlainAuth("", "user", "pass", "smtp.example.com"),
"from@example.com", []string{"admin@example.com"}, []byte(msg))
if err != nil {
http.Error(w, "Email sending failed", 500)
return
}
w.Write([]byte("Email sent successfully"))
}For Chi applications, integrate this validation as middleware to ensure consistent protection across all email-related endpoints:
func EmailInjectionProtection(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
r.ParseForm()
// Check all form values for newline injection
for key, values := range r.Form {
for _, value := range values {
if strings.Contains(value, "\n") || strings.Contains(value, "\r") {
http.Error(w, "Input contains invalid characters", 400)
return
}
}
}
}
next.ServeHTTP(w, r)
})
}
// In your Chi router setup:
r := chi.NewRouter()
r.Use(EmailInjectionProtection)
r.Post("/contact", sendSecureEmail)
Consider using a dedicated email library that handles header construction safely. Libraries like mailjet, sendgrid, or Go's net/smtp with structured construction prevent many injection vectors:
import "gopkg.in/mail.v2"
func sendSecureEmailWithLibrary(w http.ResponseWriter, r *http.Request) {
m := mail.NewMessage()
// Set headers using library methods (not string interpolation)
m.SetHeader("From", email)
m.SetHeader("To", "admin@example.com")
m.SetHeader("Subject", subject)
m.SetBody("text/plain", message)
d := mail.NewDialer("smtp.example.com", 587, "user", "pass")
if err := d.DialAndSend(m); err != nil {
http.Error(w, "Email sending failed", 500)
return
}
w.Write([]byte("Email sent successfully"))
}For Chi applications using context values, validate before using:
func ValidateContextEmail(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if email := r.Context().Value("userEmail"); email != nil {
emailStr := email.(string)
if !isValidEmail(emailStr) {
http.Error(w, "Invalid email in context", 400)
return
}
}
next.ServeHTTP(w, r)
})
}
func isValidEmail(email string) bool {
if strings.Contains(email, "\n") || strings.Contains(email, "\r") {
return false
}
if _, err := mail.ParseAddress(email); err != nil {
return false
}
return true
}Finally, implement runtime monitoring with middleBrick's continuous scanning to detect if any injection vulnerabilities are introduced during development. The Pro plan's scheduled scanning can alert you if email injection vulnerabilities appear in your Chi API endpoints.