Email Injection in Gin
How Email Injection Manifests in Gin
Email injection in Gin applications typically occurs when user input is incorporated into email headers without proper validation. This vulnerability allows attackers to inject additional email headers, enabling email spoofing, spam distribution, and even data exfiltration through crafted email bodies.
In Gin applications, this often appears in contact forms, password reset flows, or notification systems. The most common vectors are query parameters, form data, and JSON request bodies that get concatenated into email headers or content.
func contactHandler(c *gin.Context) {
name := c.PostForm("name")
email := c.PostForm("email")
message := c.PostForm("message")
// VULNERABLE: Direct concatenation without validation
subject := "Contact from: " + name
body := fmt.Sprintf("Email: %s\nMessage: %s", email, message)
// Send email - attacker can inject headers via name field
sendEmail("[email protected]", subject, body)
}
The vulnerability manifests when an attacker submits input containing newline characters ( ). For example, submitting a name like:
John Doe
Cc: [email protected]
Attacker message hereThis injects additional headers into the email, causing it to be sent to unintended recipients. The same principle applies to the message body, where attackers can inject content that gets interpreted as separate headers or even attempts to exploit SMTP servers.
Another Gin-specific manifestation occurs when using JSON payloads for email operations:
type EmailRequest struct {
From string `json:"from"`
To string `json:"to"`
Subject string `json:"subject"`
Body string `json:"body"`
}
func sendEmailHandler(c *gin.Context) {
var req EmailRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": "Invalid request"})
return
}
// VULNERABLE: No validation of header injection
sendEmail(req.To, req.Subject, req.Body)
}
Attackers can craft JSON with newline characters in the To or Subject fields to manipulate email headers. This becomes particularly dangerous when combined with misconfigured SMTP servers that allow arbitrary header injection.
Gin-Specific Detection
Detecting email injection in Gin applications requires both static analysis of your codebase and dynamic scanning of running endpoints. For static analysis, look for patterns where user input flows directly into email operations without validation.
middleBrick's API security scanner can detect email injection vulnerabilities in your Gin applications by testing for header injection patterns. The scanner sends payloads containing newline characters and special sequences to identify if your endpoints are vulnerable to header manipulation.
npm install -g middlebrick
middlebrick scan https://your-api.com/contact
The scanner tests for common injection patterns including:
- Newline character injection ( ) in header fields
- Header field injection (To, Cc, Bcc, Subject)
- Content injection in email bodies
- SMTP command injection attempts
middleBrick specifically checks for 12 security categories including Authentication, BOLA/IDOR, and Input Validation - the latter being directly relevant to email injection. The scanner provides a security score (A-F) with detailed findings about each vulnerability discovered.
For runtime detection, implement logging that flags suspicious patterns in email-related inputs:
func validateEmailInput(input string) error {
// Check for newline characters
if strings.Contains(input, "\r") || strings.Contains(input, "\n") {
return errors.New("input contains newline characters")
}
// Check for suspicious header-like patterns
if strings.Contains(input, "Cc:") || strings.Contains(input, "Bcc:") ||
strings.Contains(input, "Content-Type:") {
return errors.New("input contains suspicious header patterns")
}
return nil
}
Integrate this validation into your Gin middleware for email-related endpoints. middleBrick's continuous monitoring (Pro plan) can automatically scan your API endpoints on a schedule, alerting you when new vulnerabilities are discovered.
Gin-Specific Remediation
Remediating email injection in Gin requires a defense-in-depth approach. Start with input validation using Gin's built-in validation features combined with custom sanitization.
First, implement strict validation on all email-related inputs:
import (
"github.com/go-playground/validator/v10"
"github.com/gin-gonic/gin"
)
var validate = validator.New()
type EmailRequest struct {
Name string `json:"name" validate:"required,max=100,alphanum"`
Email string `json:"email" validate:"required,email"`
Subject string `json:"subject" validate:"required,max=200"`
Message string `json:"message" validate:"required,max=1000"`
}
func sanitizeInput(input string) string {
// Remove newline characters
input = strings.ReplaceAll(input, "\r", "")
input = strings.ReplaceAll(input, "\n", "")
// Remove suspicious header patterns
input = strings.ReplaceAll(input, "Cc:", "")
input = strings.ReplaceAll(input, "Bcc:", "")
input = strings.ReplaceAll(input, "Content-Type:", "")
return input
}
func secureEmailHandler(c *gin.Context) {
var req EmailRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": "Invalid input"})
return
}
// Validate input
if err := validate.Struct(req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// Sanitize all inputs
req.Name = sanitizeInput(req.Name)
req.Subject = sanitizeInput(req.Subject)
req.Message = sanitizeInput(req.Message)
// Send email securely
err := sendEmail("[email protected]", req.Subject,
fmt.Sprintf("From: %s <%s>\nMessage: %s", req.Name, req.Email, req.Message))
if err != nil {
c.JSON(500, gin.H{"error": "Failed to send email"})
return
}
c.JSON(200, gin.H{"status": "email sent"})
}
For form submissions, use Gin's binding validation with custom validators:
func validateNoNewlines(fl validator.FieldLevel) bool {
value := fl.Field().String()
return !strings.Contains(value, "\n") && !strings.Contains(value, "\r")
}
func main() {
validate.RegisterValidation("no_newlines", validateNoNewlines)
r := gin.Default()
r.POST("/contact", secureEmailHandler)
r.Run()
}
Implement a security middleware that checks all email-related endpoints:
func emailSecurityMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
if strings.Contains(c.Request.URL.Path, "email") ||
strings.Contains(c.Request.URL.Path, "contact") {
// Check for suspicious patterns in all form data
if err := checkSuspiciousInput(c.Request.Form); err != nil {
c.JSON(400, gin.H{"error": "Suspicious input detected"})
c.Abort()
return
}
}
c.Next()
}
}
For production deployments, integrate middleBrick's GitHub Action to scan your API endpoints during CI/CD:
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run middleBrick Scan
run: |
npm install -g middlebrick
middlebrick scan https://staging.your-api.com --fail-below B
This ensures email injection vulnerabilities are caught before deployment. The Pro plan's continuous monitoring can alert you if attackers discover and exploit any remaining vulnerabilities in production.