{"id":"GHSA-w437-9mwm-j6vq","summary":"pgEdge RAG Server shared keyword index leaked results between concurrent unauthenticated requests","details":"### Impact\n\nDocuments belonging to one caller could be returned to another. Where an application passes a customer or tenant identifier as a search filter, that scoping could be defeated by ordinary concurrent traffic. **No injection and no malformed input are required** — normal load is enough.\n\nThe BM25 keyword index was a single per-pipeline object shared by every request. A request cleared it, refilled it from its own filtered corpus and then searched it, taking a separate lock for each step rather than holding the sequence as a unit. Concurrent requests therefore interleaved, and a search could run against a corpus that a different request's filter had populated.\n\n**Who is affected:** any deployment of pgEdge RAG Server at `1.0.0` or earlier, including all alpha and beta pre-releases, that serves concurrent queries — most acutely those relying on a search filter to separate tenants or customers. The query endpoint is unauthenticated in the affected versions (`internal/server/middleware.go:37` applies logging, panic recovery and optional CORS only), so both the party whose results leak and the party receiving them are anonymous remote callers.\n\n### Patches\n\n**Fixed in `2.0.0`. Upgrade to `2.0.0` or later.**\n\nThe index is now built per request rather than shared. The regression is pinned by `TestSearch_ConcurrentRequestsDoNotShareKeywordIndex` in `internal/pipeline/orchestrator_test.go`.\n\n**Upgrading does not tell a developer whether or not their application affected, and needs action beyond upgrading.** If a consuminag application scopes results by tenant, treat responses served under concurrent load on any affected version as potentially having included another tenant's documents. **Affected responses cannot be identified from the server's own logs**, so there is no retrospective check available.\n\n### Workarounds\n\nSet `hybrid_enabled: false` on the pipeline, which skips the keyword arm and with it the shared index. Callers can also pass `disable_hybrid` per request, which can only ever turn the arm off.\n\nNeither is a substitute for upgrading.","aliases":["CVE-2026-125325"],"modified":"2026-11-12T19:45:03.186145298Z","published":"2026-11-12T19:42:07Z","database_specific":{"cwe_ids":["CWE-362","CWE-488"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-11-12T19:42:07Z","nvd_published_at":"2026-11-10T18:17:33Z"},"references":[{"type":"WEB","url":"https://github.com/pgEdge/pgedge-rag-server/security/advisories/GHSA-w437-9mwm-j6vq"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-125325"},{"type":"WEB","url":"https://github.com/pgEdge/pgedge-rag-server/pull/44"},{"type":"WEB","url":"https://github.com/pgEdge/pgedge-rag-server/commit/a09d4872356b510c81f11591845445c33ff45a84"},{"type":"PACKAGE","url":"https://github.com/pgEdge/pgedge-rag-server"},{"type":"WEB","url":"https://github.com/pgEdge/pgedge-rag-server/releases/tag/v2.0.0"}],"affected":[{"package":{"name":"github.com/pgEdge/pgedge-rag-server","ecosystem":"Go","purl":"pkg:golang/github.com/pgEdge/pgedge-rag-server"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.0.1-0.20260729020411-a09d4872356b"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-w437-9mwm-j6vq/GHSA-w437-9mwm-j6vq.json"}}],"schema_version":"1.9.2","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"}]}