Log Injection in Chi with Basic Auth
Log Injection in Chi with Basic Auth — how this specific combination creates or exposes the vulnerability
Log injection occurs when an attacker can insert newline or control characters into log entries, enabling log forging, log poisoning, or log splitting. In the Chi web framework for Go, this risk is amplified when Basic Authentication is used because the framework often records request metadata (method, path, user, and auth state) as part of request logging. If user-controlled data from the Authorization header or related request fields are written directly into structured logs without sanitization, an attacker can inject crafted lines that alter log structure or inject additional entries.
Chi does not provide built-in sanitization for Basic Auth credentials in log hooks. A typical pattern is to use RequestID and Logger middleware together, where a custom logging function may include values extracted from the request context. For example, the Basic Auth username extracted via BasicAuth can be appended to log lines. If that username contains carriage returns or line feeds (e.g., admin%0D%0AInjected: true), and the logging library writes each log entry line-by-line, the injected newline can start a new log entry, potentially obscuring the origin of the request or enabling log splitting attacks.
Consider a Chi route that uses Basic Auth and logs the authenticated user. If the logging function is implemented naively, such as directly concatenating the username into a log string and writing it to os.Stdout or a structured logger that does not escape newlines, an attacker who controls the Authorization header can craft a request like Authorization: Basic YWRtaW46ZG93biB0aGlzIGlzIGEgaW52YWxpZA== (where the decoded password contains newline characters). The injected newline can split one log line into two, causing the second line to appear as a separate, potentially misleading log entry. In distributed environments where logs are aggregated, this can complicate forensic analysis and allow an attacker to evade detection by creating noise or hiding follow-up actions.
The interaction between Chi middleware and Basic Auth exacerbates this when logging includes request-scoped values without validation. For instance, logging the authenticated username, client IP, and timestamp in a single structured entry is common. If the username is not sanitized, and the logging backend treats newline characters as record separators, the attacker can influence how logs are parsed. This is particularly relevant when logs are used for security monitoring, as injected entries may bypass correlation rules or trigger false negatives. The vulnerability is not in Chi itself but in how developers wire logging and authentication, especially when handling user-controlled data from headers before writing it to logs.
To mitigate log injection in this context, developers must treat all data entering log lines as untrusted, including values derived from Basic Auth. Sanitization should occur at the point of logging, not at the authentication layer. This means removing or escaping newline characters and other control characters from usernames and any other logged fields. Structured logging formats like JSON can reduce risk if the logging library properly escapes characters, but developers must ensure that the serialization step does not introduce ambiguities. Chi's extensibility allows for custom middleware that cleans sensitive header values before they reach log hooks, preserving auditability while preventing injection.
Basic Auth-Specific Remediation in Chi — concrete code fixes
Remediation focuses on sanitizing user-controlled data before it reaches logging, while preserving necessary authentication context. When using Basic Auth in Chi, extract credentials safely and normalize or escape them before inclusion in logs. Below are concrete, working examples demonstrating secure logging practices.
First, a vulnerable pattern that logs the raw Basic Auth username without sanitization:
import (
"net/http"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func unsafeHandler(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Vulnerable: logging raw username may contain newlines
middleware.Logger.Info("auth attempt", "username", username, "path", r.URL.Path)
// ... handle request
}
In this example, if username contains newline characters, the log entry can be split. A secure approach sanitizes the username by removing control characters before logging:
import (
"net/http"
"regexp"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
var controlChars = regexp.MustCompile(`[\r\n\x00-\x1F\x7F]`)
func sanitizeLog(s string) string {
return controlChars.ReplaceAllString(s, "")
}
func safeHandler(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Sanitize before logging
safeUser := sanitizeLog(username)
middleware.Logger.Info("auth attempt", "username", safeUser, "path", r.URL.Path)
// Proceed with authentication using original credentials
if !isValidUser(username, password) {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
// ... handle request
}
For structured JSON logging, ensure your logging library escapes characters, but explicit sanitization remains a robust defense. You can also wrap the Basic Auth extraction to normalize credentials for audit trails without compromising security:
func basicAuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, _, ok := r.BasicAuth()
if !ok {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
ctx := context.WithValue(r.Context(), "auth_user", sanitizeLog(username))
next.ServeHTTP(w, r.WithContext(ctx))
})
}
Additionally, configure your logging middleware to avoid including raw headers. Chi's middleware stack allows ordering: place sanitization before logging so that no raw newline characters reach log hooks. This approach aligns with secure handling of credentials while maintaining the ability to audit authentication events.