{"id":"CVE-2026-125325","aliases":["EUVD-2026-121707","GHSA-w437-9mwm-j6vq"],"status":"published","title":"pgEdge RAG Server shared keyword index leaked results between concurrent unauthenticated requests","description":"pgEdge RAG Server is an API server for retrieval-augmented generation over PostgreSQL content using pgvector. Prior to 2.0.0, the BM25 keyword index is a single per-pipeline object shared by the unauthenticated query endpoint, and concurrent requests lock its clear, refill, and search operations separately. This allows one request to search a corpus populated through another request's search filter, which can return documents belonging to a different tenant or customer without malformed input. The affected responses cannot be identified retrospectively from the server logs. This issue is fixed in version 2.0.0.","severity":{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00271,"percentile":0.19594,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-362","CWE-488"],"published":"2026-11-10T17:58:40.428Z","modified":"2026-11-12T19:45:03Z","fixes":[{"ecosystem":"Go","package":"github.com/pgEdge/pgedge-rag-server","fixed_in":["1.0.1-0.20260729020411-a09d4872356b"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Go","package":"github.com/pgEdge/pgedge-rag-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.0.1-0.20260729020411-a09d4872356b"}]}]},{"source":"osv","ecosystem":"Go","package":"github.com/pgEdge/pgedge-rag-server","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.0.1-0.20260729020411-a09d4872356b"}]}]}],"products":[{"vendor":"pgedge","product":"pgedge-rag-server"}],"references":[{"url":"https://github.com/pgEdge/pgedge-rag-server/security/advisories/GHSA-w437-9mwm-j6vq","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/pgEdge/pgedge-rag-server/pull/44","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/pgEdge/pgedge-rag-server/commit/a09d4872356b510c81f11591845445c33ff45a84","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/pgEdge/pgedge-rag-server/releases/tag/v2.0.0","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-125325","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-w437-9mwm-j6vq"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/125xxx/CVE-2026-125325.json","tags":["advisory"]},{"url":"https://github.com/pgEdge/pgedge-rag-server","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-125325","title":"pgEdge RAG Server shared keyword index leaked results between concurrent unauthenticated requests","description":"pgEdge RAG Server is an API server for retrieval-augmented generation over PostgreSQL content using pgvector. Prior to 2.0.0, the BM25 keyword index is a single per-pipeline object shared by the unauthenticated query endpoint, and concurrent requests lock its clear, refill, and search operations separately. This allows one request to search a corpus populated through another request's search filter, which can return documents belonging to a different tenant or customer without malformed input. The affected responses cannot be identified retrospectively from the server logs. This issue is fixed in version 2.0.0.","status":"published","published":"2026-11-10T17:58:40.428Z","modified":"2026-11-10T17:58:40.428Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-362","CWE-488"],"updated_at":"2026-11-10T18:39:47.416646Z"}],"euvd":[{"id":"EUVD-2026-121707","description":"pgEdge RAG Server shared keyword index leaked results between concurrent unauthenticated requests","status":"published","published":"2026-11-12T19:42:07Z","modified":"2026-11-12T19:42:08Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"medium"}],"updated_at":"2026-11-12T21:35:37.836294Z"}],"ghsa":[{"id":"GHSA-w437-9mwm-j6vq","title":"pgEdge RAG Server shared keyword index leaked results between concurrent unauthenticated requests","description":"### 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.","status":"published","published":"2026-11-12T19:42:07Z","modified":"2026-11-12T19:42:08Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-362","CWE-488"],"updated_at":"2026-11-12T19:42:54.373923Z"}],"nvd":[{"id":"CVE-2026-125325","description":"pgEdge RAG Server is an API server for retrieval-augmented generation over PostgreSQL content using pgvector. Prior to 2.0.0, the BM25 keyword index is a single per-pipeline object shared by the unauthenticated query endpoint, and concurrent requests lock its clear, refill, and search operations separately. This allows one request to search a corpus populated through another request's search filter, which can return documents belonging to a different tenant or customer without malformed input. The affected responses cannot be identified retrospectively from the server logs. This issue is fixed in version 2.0.0.","status":"published","published":"2026-11-10T18:17:33.857Z","modified":"2026-11-12T22:18:51.47Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-362","CWE-488"],"updated_at":"2026-11-10T20:21:09.613171Z"}],"osv":[{"id":"CVE-2026-125325","title":"pgEdge RAG Server shared keyword index leaked results between concurrent unauthenticated requests","description":"pgEdge RAG Server is an API server for retrieval-augmented generation over PostgreSQL content using pgvector. Prior to 2.0.0, the BM25 keyword index is a single per-pipeline object shared by the unauthenticated query endpoint, and concurrent requests lock its clear, refill, and search operations separately. This allows one request to search a corpus populated through another request's search filter, which can return documents belonging to a different tenant or customer without malformed input. The affected responses cannot be identified retrospectively from the server logs. This issue is fixed in version 2.0.0.","status":"published","published":"2026-11-10T17:58:40.428Z","modified":"2026-11-12T02:48:34.737492926Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-362","CWE-488"],"updated_at":"2026-11-12T03:30:48.739835Z"},{"id":"GHSA-w437-9mwm-j6vq","title":"pgEdge RAG Server shared keyword index leaked results between concurrent unauthenticated requests","description":"### 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.","status":"published","published":"2026-11-12T19:42:07Z","modified":"2026-11-12T19:45:03.186145298Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-362","CWE-488"],"updated_at":"2026-11-12T20:14:41.935484Z"}]}}
