Skip to content

Commit 59c12ea

Browse files
committed
fix operator security: path escape + sendEvent app-key bypass
- ArgoCD executor: use url.PathEscape for app name in API paths to prevent path traversal - Datadog executor: use url.PathEscape for monitor ID in mute path - Datadog executor: allow sendEvent to bypass app-key gate since it only needs DD-API-KEY (doPost with needsAppKey=false) Made-with: Cursor
1 parent db373c5 commit 59c12ea

2 files changed

Lines changed: 8 additions & 4 deletions

File tree

pkg/argocd_executor/argocd_executor.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io"
99
"net/http"
10+
"net/url"
1011
"strings"
1112
"sync"
1213
"time"
@@ -323,7 +324,7 @@ func (e *ArgoCDExecutor) getAppStatus(ctx context.Context, req *v1.DatadogQueryR
323324
zap.String("request_id", req.RequestId),
324325
zap.String("app_name", appName))
325326

326-
path := fmt.Sprintf("/api/v1/applications/%s", appName)
327+
path := fmt.Sprintf("/api/v1/applications/%s", url.PathEscape(appName))
327328
body, code, err := e.doGet(ctx, path)
328329
return e.makeResponse(req.RequestId, body, code, err)
329330
}
@@ -348,7 +349,7 @@ func (e *ArgoCDExecutor) syncApp(ctx context.Context, req *v1.DatadogQueryReques
348349
zap.String("request_id", req.RequestId),
349350
zap.String("app_name", appName))
350351

351-
path := fmt.Sprintf("/api/v1/applications/%s/sync", appName)
352+
path := fmt.Sprintf("/api/v1/applications/%s/sync", url.PathEscape(appName))
352353
body, code, err := e.doPost(ctx, path, []byte(syncBody))
353354
return e.makeResponse(req.RequestId, body, code, err)
354355
}

pkg/datadog_executor/datadog_executor.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ func (e *DatadogExecutor) ExecuteQuery(ctx context.Context, req *v1.DatadogQuery
8989
e.mu.RLock()
9090
hasAppKey := e.appKey != ""
9191
e.mu.RUnlock()
92-
if !hasAppKey {
92+
93+
// sendEvent only needs the API key; all other operations require the app key
94+
needsAppKey := req.QueryType != v1.DatadogQueryType_DATADOG_SEND_EVENT
95+
if needsAppKey && !hasAppKey {
9396
e.Logger.Warn("Datadog query requires app key but none available",
9497
zap.String("request_id", req.RequestId),
9598
zap.String("query_type", req.QueryType.String()))
@@ -775,7 +778,7 @@ func (e *DatadogExecutor) muteMonitor(ctx context.Context, req *v1.DatadogQueryR
775778
muteBody = "{}"
776779
}
777780

778-
apiPath := fmt.Sprintf("/api/v1/monitor/%s/mute", monitorID)
781+
apiPath := fmt.Sprintf("/api/v1/monitor/%s/mute", url.PathEscape(monitorID))
779782
e.Logger.Info("[Datadog] Muting monitor",
780783
zap.String("request_id", req.RequestId),
781784
zap.String("monitor_id", monitorID))

0 commit comments

Comments
 (0)