highCVE-2026-44300Jul 14, 2026

CVE-2026-44300: OpenCost Unauthenticated GCP Service Key Overwrite

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

OpenCost's /serviceKey endpoint lets anyone on the network overwrite the GCP service account credentials file with no authentication required, which can disrupt cost monitoring or redirect billing dat

Packagegithub.com/opencost/opencost
Ecosystemgo
Affected< 1.119.1
Fixed in1.119.1

The problem

The `AddServiceKey` handler in `pkg/costmodel/router.go` reads a user-supplied `key` form field and writes it straight to disk via `os.WriteFile` with no authentication check whatsoever. The target path is `<CONFIG_PATH>/key.json`, defaulting to `/var/configs/key.json`.

Any client that can reach port 9003 can overwrite the GCP credentials file. In clusters where the service is exposed via Ingress or NodePort, that means the internet. Even in cluster-internal deployments, any compromised pod becomes a stepping stone.

Proof of concept

A working proof-of-concept for CVE-2026-44300 in github.com/opencost/opencost, with the exact payload below.

bash
# Overwrite key.json with attacker-controlled GCP credentials (no auth required)
curl -X POST http://<opencost-host>:9003/serviceKey \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'key={"type":"service_account","project_id":"attacker-project","private_key_id":"abc123","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n","client_email":"hijack@attacker-project.iam.gserviceaccount.com","token_uri":"https://oauth2.googleapis.com/token"}'

The root cause is CWE-306: the handler performs no authentication before a destructive write. The vulnerable code calls `r.PostForm.Get("key")` then directly passes the bytes to `os.WriteFile(env.GetGCPAuthSecretFilePath(), k, 0644)`. No token check, no JSON schema validation, no CORS restriction beyond `Access-Control-Allow-Origin: *`.

The patch introduced an `ADMIN_TOKEN` environment variable. The handler now checks the `Authorization: Bearer <token>` header against that value before allowing the write. The Helm chart wires this up via the new `adminToken` block (disabled by default, so operators must explicitly opt in to protect the endpoint).

The fix

Upgrade to OpenCost 1.119.1 or later. After upgrading, set the `ADMIN_TOKEN` environment variable (or use the Helm chart's `opencost.exporter.adminToken` block) to enable the bearer-token guard on `/serviceKey` and other write endpoints. If you cannot upgrade immediately, block access to port 9003 with a Kubernetes NetworkPolicy or remove the route at the ingress layer.

Reporter not attributed.

References: [1][2]

Related research