sec5e: sanitize log-injection in client, discovery, testutils, cmd

Fixes CodeQL go/log-injection alerts in the final batch of packages.

New logutil.go helpers: pkg/client, pkg/testutils/amazon,
pkg/testutils/spotify, cmd/soundtouch-service, cmd/soundtouch-web,
cmd/dummy-speaker, cmd/mdns-scanner.

pkg/discovery/logger.go: added sanitizeLog and a nil-safe
remoteAddrString helper to the existing file (alongside logVerbose).

Call sites wrapped across 11 files — device IDs, source types,
hostnames, IPs, interface names, URLs, service names, HTTP method/form
values, WebSocket URLs and payloads, TLS SNI names, remote addresses.

No behaviour change. golangci-lint and make check pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tobias Gesellchen
2026-05-24 17:29:39 +02:00
co-authored by Claude Sonnet 4.6
parent 3d8e08d11a
commit dc8ec69c61
18 changed files with 185 additions and 71 deletions
+3 -3
View File
@@ -23,7 +23,7 @@ func NewAmazonHandler() http.Handler {
// HandleToken simulates the Amazon LWA token endpoint.
// Amazon requires client_id and client_secret as POST body fields, not HTTP Basic Auth.
func HandleToken(w http.ResponseWriter, r *http.Request) {
log.Printf("[Amazon Mock] Token request: %s", r.Method)
log.Printf("[Amazon Mock] Token request: %s", sanitizeLog(r.Method))
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
@@ -36,7 +36,7 @@ func HandleToken(w http.ResponseWriter, r *http.Request) {
}
grantType := r.FormValue("grant_type")
log.Printf("[Amazon Mock] Grant type: %s", grantType)
log.Printf("[Amazon Mock] Grant type: %s", sanitizeLog(grantType))
resp := map[string]interface{}{
"access_token": "Atza|amazon-access-token",
@@ -71,7 +71,7 @@ func HandleToken(w http.ResponseWriter, r *http.Request) {
// HandleProfile simulates the Amazon LWA user profile endpoint.
// LWA returns "user_id" and "name" (not "id" / "display_name" like Spotify).
func HandleProfile(w http.ResponseWriter, r *http.Request) {
log.Printf("[Amazon Mock] Profile request: %s", r.Method)
log.Printf("[Amazon Mock] Profile request: %s", sanitizeLog(r.Method))
auth := r.Header.Get("Authorization")
if auth != "Bearer Atza|amazon-access-token" {
+13
View File
@@ -0,0 +1,13 @@
package amazon
import "strings"
// sanitizeLog strips newline characters from s to prevent log-injection
// (CodeQL go/log-injection). Values from speakers, HTTP requests, and
// external APIs may contain attacker-controlled newlines.
func sanitizeLog(s string) string {
s = strings.ReplaceAll(s, "\n", `\n`)
s = strings.ReplaceAll(s, "\r", `\r`)
return s
}
+3 -3
View File
@@ -23,7 +23,7 @@ func NewSpotifyHandler() http.Handler {
// HandleToken simulates the Spotify OAuth token endpoint.
func HandleToken(w http.ResponseWriter, r *http.Request) {
log.Printf("[Spotify Mock] Token request: %s", r.Method)
log.Printf("[Spotify Mock] Token request: %s", sanitizeLog(r.Method))
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
@@ -36,7 +36,7 @@ func HandleToken(w http.ResponseWriter, r *http.Request) {
}
grantType := r.FormValue("grant_type")
log.Printf("[Spotify Mock] Grant type: %s", grantType)
log.Printf("[Spotify Mock] Grant type: %s", sanitizeLog(grantType))
resp := map[string]interface{}{
"access_token": "spotify-access-token",
@@ -73,7 +73,7 @@ func HandleToken(w http.ResponseWriter, r *http.Request) {
// HandleMe simulates the Spotify user profile endpoint.
func HandleMe(w http.ResponseWriter, r *http.Request) {
log.Printf("[Spotify Mock] Profile request: %s", r.Method)
log.Printf("[Spotify Mock] Profile request: %s", sanitizeLog(r.Method))
auth := r.Header.Get("Authorization")
if auth != "Bearer spotify-access-token" {
+13
View File
@@ -0,0 +1,13 @@
package spotify
import "strings"
// sanitizeLog strips newline characters from s to prevent log-injection
// (CodeQL go/log-injection). Values from speakers, HTTP requests, and
// external APIs may contain attacker-controlled newlines.
func sanitizeLog(s string) string {
s = strings.ReplaceAll(s, "\n", `\n`)
s = strings.ReplaceAll(s, "\r", `\r`)
return s
}