Skip to content

Commit eb2bee0

Browse files
authored
fix(security): redact sensitive URL parameters in logs (#853)
1 parent 02a68e5 commit eb2bee0

16 files changed

Lines changed: 887 additions & 251 deletions

File tree

internal/api/handlers/jackett.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
"github.com/autobrr/qui/internal/models"
2020
"github.com/autobrr/qui/internal/services/jackett"
21+
"github.com/autobrr/qui/pkg/redact"
2122
)
2223

2324
const (
@@ -858,7 +859,7 @@ func (h *JackettHandler) DiscoverIndexers(w http.ResponseWriter, r *http.Request
858859

859860
result, err := jackett.DiscoverJackettIndexers(r.Context(), req.BaseURL, req.APIKey)
860861
if err != nil {
861-
log.Error().Err(err).Str("base_url", req.BaseURL).Msg("Failed to discover indexers")
862+
log.Error().Str("base_url", redact.URLString(req.BaseURL)).Str("error", redact.String(err.Error())).Msg("Failed to discover indexers")
862863
RespondError(w, http.StatusInternalServerError, "Failed to discover indexers")
863864
return
864865
}

internal/api/handlers/torrents.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"github.com/autobrr/qui/internal/qbittorrent"
2626
"github.com/autobrr/qui/internal/services/jackett"
27+
"github.com/autobrr/qui/pkg/redact"
2728
"github.com/autobrr/qui/pkg/torrentname"
2829
)
2930

@@ -561,7 +562,7 @@ func (h *TorrentsHandler) AddTorrent(w http.ResponseWriter, r *http.Request) {
561562
if respondIfInstanceDisabled(w, err, instanceID, "torrents:addFromURLs") {
562563
return
563564
}
564-
log.Error().Err(err).Int("instanceID", instanceID).Str("url", url).Msg("Failed to add magnet link")
565+
log.Error().Err(err).Int("instanceID", instanceID).Str("url", redact.URLString(url)).Msg("Failed to add magnet link")
565566
failedURLs = append(failedURLs, failedURL{URL: url, Error: err.Error()})
566567
failedCount++
567568
lastError = err
@@ -577,7 +578,7 @@ func (h *TorrentsHandler) AddTorrent(w http.ResponseWriter, r *http.Request) {
577578
DownloadURL: url,
578579
})
579580
if err != nil {
580-
log.Error().Err(err).Int("indexerID", indexerID).Int("instanceID", instanceID).Str("url", url).Msg("Failed to download torrent from indexer")
581+
log.Error().Err(err).Int("indexerID", indexerID).Int("instanceID", instanceID).Str("url", redact.URLString(url)).Msg("Failed to download torrent from indexer")
581582
failedURLs = append(failedURLs, failedURL{URL: url, Error: err.Error()})
582583
failedCount++
583584
lastError = err
@@ -589,7 +590,7 @@ func (h *TorrentsHandler) AddTorrent(w http.ResponseWriter, r *http.Request) {
589590
if respondIfInstanceDisabled(w, err, instanceID, "torrents:add") {
590591
return
591592
}
592-
log.Error().Err(err).Int("instanceID", instanceID).Int("indexerID", indexerID).Str("url", url).Msg("Failed to add downloaded torrent")
593+
log.Error().Err(err).Int("instanceID", instanceID).Int("indexerID", indexerID).Str("url", redact.URLString(url)).Msg("Failed to add downloaded torrent")
593594
failedURLs = append(failedURLs, failedURL{URL: url, Error: err.Error()})
594595
failedCount++
595596
lastError = err

internal/api/middleware/logger.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010

1111
"github.com/go-chi/chi/v5/middleware"
1212
"github.com/rs/zerolog"
13+
14+
"github.com/autobrr/qui/pkg/redact"
1315
)
1416

1517
// Logger logs HTTP requests using a local zerolog logger
@@ -41,7 +43,7 @@ func Logger(logger zerolog.Logger) func(next http.Handler) http.Handler {
4143
Timestamp().
4244
Fields(map[string]any{
4345
"remote_ip": r.RemoteAddr,
44-
"url": r.URL.Path,
46+
"url": redact.ProxyPath(r.URL.Path),
4547
"proto": r.Proto,
4648
"method": r.Method,
4749
"user_agent": r.Header.Get("User-Agent"),

internal/metrics/server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"github.com/go-chi/chi/v5/middleware"
1414
"github.com/prometheus/client_golang/prometheus/promhttp"
1515
"github.com/rs/zerolog/log"
16+
17+
"github.com/autobrr/qui/pkg/redact"
1618
)
1719

1820
type Server struct {
@@ -34,7 +36,7 @@ func NewMetricsServer(manager *MetricsManager, host string, port int, basicAuthU
3436
if len(parts) == 2 {
3537
s.basicAuthUsers[parts[0]] = parts[1]
3638
} else {
37-
log.Warn().Msgf("Invalid metrics basic auth credentials: %s", cred)
39+
log.Warn().Msgf("Invalid metrics basic auth credentials: %s", redact.BasicAuthUser(cred))
3840
}
3941
}
4042
}

internal/proxy/handler.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/autobrr/qui/internal/qbittorrent"
2929
"github.com/autobrr/qui/internal/services/reannounce"
3030
"github.com/autobrr/qui/pkg/httphelpers"
31+
"github.com/autobrr/qui/pkg/redact"
3132
)
3233

3334
// Handler manages reverse proxy requests to qBittorrent instances
@@ -149,8 +150,7 @@ func (h *Handler) rewriteRequest(pr *httputil.ProxyRequest) {
149150
log.Debug().
150151
Str("client", clientAPIKey.ClientName).
151152
Int("instanceId", instanceID).
152-
Str("originalPath", originalPath).
153-
Str("strippedPath", strippedPath).
153+
Str("strippedPath", redact.ProxyPath(strippedPath)).
154154
Str("targetHost", instanceURL.Host).
155155
Msg("Rewriting proxy request")
156156

@@ -262,11 +262,10 @@ func (h *Handler) errorHandler(w http.ResponseWriter, r *http.Request, err error
262262
}
263263

264264
log.Error().
265-
Err(err).
265+
Str("error", redact.String(err.Error())).
266266
Str("client", clientName).
267267
Int("instanceId", instanceID).
268268
Str("method", r.Method).
269-
Str("path", r.URL.Path).
270269
Msg("Proxy request failed")
271270

272271
h.writeProxyError(w)
@@ -423,7 +422,6 @@ func (h *Handler) prepareProxyContext(r *http.Request) (*proxyContext, error) {
423422
logger := log.With().
424423
Int("instanceId", instanceID).
425424
Str("method", r.Method).
426-
Str("path", r.URL.Path).
427425
Logger()
428426

429427
if clientAPIKey != nil {

internal/proxy/middleware.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,20 +104,17 @@ func ClientAPIKeyMiddleware(store *models.ClientAPIKeyStore) func(http.Handler)
104104
return func(next http.Handler) http.Handler {
105105
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
106106
log.Debug().
107-
Str("fullPath", r.URL.Path).
108107
Str("method", r.Method).
109108
Msg("ClientAPIKeyMiddleware called")
110109

111110
// Extract API key from URL path parameter
112111
apiKey := chi.URLParam(r, "api-key")
113112
log.Debug().
114-
Str("apiKey", apiKey).
115-
Bool("isEmpty", apiKey == "").
116-
Msg("Extracted API key from URL parameter")
113+
Bool("hasKey", apiKey != "").
114+
Msg("Checking API key from URL parameter")
117115

118116
if apiKey == "" {
119117
log.Warn().
120-
Str("path", r.URL.Path).
121118
Str("user_agent", userAgentOrUnknown(r)).
122119
Msg("Missing API key in proxy request")
123120
http.Error(w, "Missing API key", http.StatusUnauthorized)
@@ -130,7 +127,6 @@ func ClientAPIKeyMiddleware(store *models.ClientAPIKeyStore) func(http.Handler)
130127
if err != nil {
131128
if err == models.ErrClientAPIKeyNotFound {
132129
log.Warn().
133-
Str("key_prefix", apiKey[:min(8, len(apiKey))]).
134130
Str("user_agent", userAgentOrUnknown(r)).
135131
Msg("Invalid client API key")
136132
http.Error(w, "Invalid API key", http.StatusUnauthorized)
@@ -156,7 +152,6 @@ func ClientAPIKeyMiddleware(store *models.ClientAPIKeyStore) func(http.Handler)
156152
Str("client", clientAPIKey.ClientName).
157153
Int("instanceId", clientAPIKey.InstanceID).
158154
Str("method", r.Method).
159-
Str("path", r.URL.Path).
160155
Msg("Client API key validated successfully")
161156

162157
// Add client API key and instance ID to request context

0 commit comments

Comments
 (0)