{ "schema_version": "1.4.0", "id": "GHSA-mhc4-g3wh-cw7m", "modified": "2026-09-02T15:26:56Z", "published": "2026-08-18T20:50:54Z", "aliases": [ "CVE-2026-65959" ], "summary": "Vitess: Missing authorization on vttablet /debug/vrlog exposes live VReplication SQL data", "details": "## Vulnerability Details\n\n**File**: `go/vt/vttablet/tabletmanager/vreplication/vrlog.go`\n\n### Summary\n`vttablet`'s `/debug/vrlog` HTTP endpoint streams live VReplication event data — including the literal SQL DML statements being replicated by MoveTables, Reshard, Materialize, and \"vitess\"-strategy Online DDL workflows — with no authorization check at all. Every comparable \"debugging\" HTTP endpoint in vttablet/vtgate (querylogz, queryz, txlogz, livequeryz, schemaz, debugenv, hotrows, tablet_plans, query_stats, query_rules) calls `acl.CheckAccessHTTP(r, acl.DEBUGGING)` before serving data, so that the cluster operator's configured `--security-policy` (e.g. `deny-all`, `read-only`, or a custom plugin) is actually honored. `vrlog.go` is the one exception: it has zero references to the `acl` package.\n\n### Root Cause\n`addHttpEndpoint()` registers `/debug/vrlog` via `servenv.HTTPHandleFunc`, and `vrlogStatsHandler()` immediately starts streaming subscribed `VrLogStats` events to the response writer without first calling `acl.CheckAccessHTTP(r, acl.DEBUGGING)`, unlike every sibling handler in the same family (see e.g. `go/vt/vttablet/tabletserver/querylogz.go`'s `querylogzHandler`, which calls the check first).\n\nThe data streamed is sensitive: `go/vt/vttablet/tabletmanager/vreplication/vplayer.go` calls `NewVrLogStats(...).Send(sql)` / `.Send(event.Statement)` for every row change and statement event flowing through a VReplication stream (vplayer.go:339, 700, 771, 785) — i.e. the literal SQL (including bound data values) being copied/replicated by MoveTables, Reshard, Materialize, and Online DDL.\n\n### Attack Scenario\n1. A cluster operator configures `--security-policy=deny-all` (or `read-only`, or a custom policy) specifically to lock down debugging/admin HTTP endpoints on vttablet, relying on this being uniformly enforced.\n2. An attacker who can reach the vttablet debug HTTP port (common in Kubernetes/Prometheus-scraping deployments where this port is exposed beyond localhost) — but who does NOT have the `DEBUGGING`/admin role the policy requires — sends `GET /debug/vrlog`.\n3. Every other debug endpoint correctly returns `403 Forbidden`. `/debug/vrlog` returns `200 OK` and streams live VReplication event data, including raw SQL DML statements containing application data values, for as long as the attacker keeps the connection open (bounded by `timeout`/`limit` query params, repeatable).\n\n### Impact\nConfidentiality impact: disclosure of live replicated application data (potentially including PII or other sensitive column values) to an unauthorized actor, bypassing an access control the operator explicitly configured. No write/modify capability; this is a read-only information-disclosure / access-control-bypass issue, scoped to the vttablet debug HTTP listener.\n\n### Vulnerable Code\n```go\n// go/vt/vttablet/tabletmanager/vreplication/vrlog.go\nfunc addHttpEndpoint() {\n\tservenv.HTTPHandleFunc(\"/debug/vrlog\", func(w http.ResponseWriter, r *http.Request) {\n\t\tch := vrLogStatsLogger.Subscribe(\"vrlogstats\")\n\t\tdefer vrLogStatsLogger.Unsubscribe(ch)\n\t\tvrlogStatsHandler(ch, w, r)\n\t})\n}\n\nfunc vrlogStatsHandler(ch chan *VrLogStats, w http.ResponseWriter, r *http.Request) {\n\ttimeout, limit := parseTimeoutLimitParams(r)\n\t// no acl.CheckAccessHTTP(r, acl.DEBUGGING) call anywhere in this file\n\t...\n```\n\n### Recommended Fix\n```go\nimport \"vitess.io/vitess/go/acl\"\n\nfunc vrlogStatsHandler(ch chan *VrLogStats, w http.ResponseWriter, r *http.Request) {\n\tif err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil {\n\t\tacl.SendError(w, err)\n\t\treturn\n\t}\n\ttimeout, limit := parseTimeoutLimitParams(r)\n\t...\n```\nThis mirrors the exact pattern already used by `querylogz.go`, `queryz.go`, `txlogz.go`, `livequeryz.go`, `schemaz.go`, `debugenv.go`, and `tx_serializer.go` (hotrows) in the same codebase.\n\n### Verification\nBuilt v24.0.1 from source and wrote a standalone Go test that: (1) activates the real `deny-all` security policy via `acl.RegisterFlags`, (2) registers `/debug/vrlog` via the real, unmodified `vreplication.NewVrLogStats(...)` call path (the same one `vplayer.go` uses for live replication traffic), (3) serves the real `servenv` HTTP mux on a loopback listener, and (4) issues a real `GET /debug/vrlog` while emitting a simulated replicated statement.\n\nResult:\n```\nacl.CheckAccessHTTP(DEBUGGING) under deny-all => err=not allowed: deny-all security-policy enforced\nGET /debug/vrlog under deny-all => status=200 body=\"ROWCHANGE Event\\tINSERT INTO secret_table (ssn) VALUES ('leaked-via-vrlog')\\t2026-06-22T11:01:55\\t147101\\n\"\n```\nThe identical ACL check that protects every sibling endpoint correctly rejected the request, while `/debug/vrlog` returned 200 and streamed the simulated sensitive content — confirming the bypass against real, unmodified v24.0.1 code.\n\nAlso confirmed via the GitHub Contents API that `vrlog.go` has zero references to the `acl` package on `main`, `release-23.0`, and `release-22.0` as well, so all currently supported release lines appear affected.", "severity": [ { "type": "CVSS_V3", "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N" } ], "affected": [ { "package": { "ecosystem": "Go", "name": "vitess.io/vitess" }, "ranges": [ { "type": "ECOSYSTEM", "events": [ { "introduced": "0.24.0-rc1" }, { "last_affected": "0.24.2" } ] } ] }, { "package": { "ecosystem": "Go", "name": "vitess.io/vitess" }, "ranges": [ { "type": "ECOSYSTEM", "events": [ { "introduced": "0" }, { "last_affected": "0.23.6" } ] } ] } ], "references": [ { "type": "WEB", "url": "https://github.com/vitessio/vitess/security/advisories/GHSA-mhc4-g3wh-cw7m" }, { "type": "ADVISORY", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-65959" }, { "type": "WEB", "url": "https://github.com/vitessio/vitess/pull/20467" }, { "type": "WEB", "url": "https://github.com/vitessio/vitess/commit/4c58cd70edc6b03d61cb65842c342ac08341e64f" }, { "type": "WEB", "url": "https://github.com/vitessio/vitess/commit/657662e78bde1c82df680e9cc43a686d619f8094" }, { "type": "WEB", "url": "https://github.com/vitessio/vitess/commit/d929225a450027406687d27af8dca45620945ceb" }, { "type": "PACKAGE", "url": "https://github.com/vitessio/vitess" } ], "database_specific": { "cwe_ids": [ "CWE-862" ], "severity": "MODERATE", "github_reviewed": true, "github_reviewed_at": "2026-08-18T20:50:54Z", "nvd_published_at": "2026-08-18T19:17:00Z" } }