{"id":"GHSA-mhc4-g3wh-cw7m","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 =\u003e err=not allowed: deny-all security-policy enforced\nGET /debug/vrlog under deny-all =\u003e 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.","aliases":["CVE-2026-65959","GO-2026-6356"],"modified":"2026-09-15T19:10:45.454473894Z","published":"2026-08-18T20:50:54Z","database_specific":{"github_reviewed_at":"2026-08-18T20:50:54Z","nvd_published_at":"2026-08-18T19:17:00Z","cwe_ids":["CWE-862"],"severity":"MODERATE","github_reviewed":true},"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"}],"affected":[{"package":{"name":"vitess.io/vitess","ecosystem":"Go","purl":"pkg:golang/vitess.io/vitess"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.24.0-rc1"},{"last_affected":"0.24.2"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-mhc4-g3wh-cw7m/GHSA-mhc4-g3wh-cw7m.json"}},{"package":{"name":"vitess.io/vitess","ecosystem":"Go","purl":"pkg:golang/vitess.io/vitess"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"last_affected":"0.23.6"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-mhc4-g3wh-cw7m/GHSA-mhc4-g3wh-cw7m.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N"}]}