Files
teamai-test/.teamai/skills/common/golang-security/references/logging.md
T

3.5 KiB

Logging Security Rules

Logging sensitive information can lead to data exposure and compliance violations.

Rules:

  1. PII MUST NEVER be logged — filter passwords, tokens, emails, and personal data.
  2. Log injection MUST be prevented — sanitize user input before logging.
  3. Error messages MUST NOT expose internals to users — log details server-side, return generic messages.

Sensitive Data in Logs — Medium

Bad:

type User struct {
    ID       string
    Username string
    Password string
    Token    string
}

func logUserLogin(user *User) {
    log.Printf("User logged in: %+v\n", user)  // DON'T: Logs password, token
}

Good:

import "log/slog"

func logUserLogin(logger *slog.Logger, user *User) {
    logger.Info("user_login",
        "user_id", user.ID,
        "username", user.Username,
        // Don't log: password, token
    )
}

Log Injection — Low

User input in logs can lead to log injection attacks.

Bad:

log.Printf("User logged in: %s\n", username)  // DON'T: No sanitization

Good:

import "log/slog"

// Sanitize user input before logging
func sanitizeLogInput(input string) string {
    // Remove control characters
    var result strings.Builder
    for _, r := range input {
        if !unicode.IsControl(r) || r == '\n' || r == '\t' {
            result.WriteRune(r)
        }
    }
    return result.String()
}

func logUsername(logger *slog.Logger, username string) {
    sanitized := sanitizeLogInput(username)
    logger.Info("user_login", "username", sanitized)
}

Information Leakage in Error Messages — Medium

Bad:

func handleDatabaseError(err error) error {
    return fmt.Errorf("database error: %v", err)  // DON'T: Leaks internal details
}

func dbErrorToHTTP(err error) {
    http.Error(w, "Error: "+err.Error(), 500)  // DON'T
}

Good:

func handleDatabaseError(logger *slog.Logger, err error) error {
    // Log detailed error for debugging
    logger.Error("database_error", "error", err.Error())
    // Return generic message to client
    return errors.New("database operation failed")
}

func dbErrorToHTTP(w http.ResponseWriter, logger *slog.Logger, err error) {
    logger.Error("database_error", "error", err.Error())
    http.Error(w, "Internal server error", http.StatusInternalServerError)
}

General Logger Security — Low

Bad:

import "log"
log.Println("User logged in:", user.ID, password)  // DON'T: Logs password
fmt.Printf("DEBUG: %+v\n", data)  // DON'T: Raw data

Good:

import "log/slog"

handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level:     slog.LevelInfo,
    AddSource: false,
})
logger := slog.New(handler)

logger.Info("user_login",
    "user_id", userID,
    "ip_address", request.RemoteIP,
)

Log Security Checklist

  • No passwords, tokens, or secrets in logs
  • No PII/PHI in production logs
  • Sanitize user input before logging
  • Use structured logging (JSON)
  • Implement log level strategy
  • Separate access logs from error logs
  • Log file permissions restricted (e.g., 600)
  • Log rotation prevents disk exhaustion
  • Generic error messages to clients
  • Detailed errors only in internal logs

CWE References

  • CWE-532: Insertion of Sensitive Information into Log File
  • CWE-117: Improper Output Neutralization for Logs
  • CWE-209: Information Exposure Through an Error Message
  • CWE-200: Exposure of Sensitive Information
  • CWE-312: Cleartext Storage of Sensitive Information