CVE-2026-125325: Cross-Request Information Disclosure via Shared BM25 Index Race Condition in pgEdge RAG Server
Vulnerability ID: CVE-2026-125325
CVSS Score: 5.9
Published: 2026-11-12
pgEdge RAG Server versions prior to 2.0.0 contain a race condition in the hybrid search pipeline orchestrator (CWE-362, CWE-488). The server maintains a single shared, in-memory BM25 index instance across all incoming HTTP requests on a pipeline. Concurrent queries to the unauthenticated HTTP REST API interleave non-atomic clear, document addition, and search operations on this singleton index. As a result, documents fetched using one caller's search filter can be queried and returned to another concurrent caller, bypassing multi-tenant data isolation without generating any anomalous audit trail in server or database logs.
TL;DR
A concurrency flaw in pgEdge RAG Server (< 2.0.0) causes concurrent hybrid search requests to share and mutate a single in-memory BM25 keyword index. Attackers or concurrent users can receive document contents and synthesized LLM answers belonging to other tenants' filtered search scopes. Upgrading to version 2.0.0 resolves the issue by isolating BM25 index instances to individual requests.
⚠️ Exploit Status: POC
Technical Details
- CVE ID: CVE-2026-125325 (GHSA-w437-9mwm-j6vq)
- Vulnerability Class: CWE-362 (Race Condition) / CWE-488 (Exposure of Data Element to Wrong Session)
- CVSS v3.1 Score: 5.9 Medium (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N)
- Attack Vector: Network (Unauthenticated HTTP POST to /v1/pipelines/{name})
- Primary Impact: Cross-request / Cross-tenant information disclosure of filtered RAG documents
- Affected Versions: pgEdge RAG Server < 2.0.0
- Patched Version: pgEdge RAG Server 2.0.0
- EPSS / KEV Status: 0.27% (19.59th percentile) / Not Listed in CISA KEV
Affected Systems
- pgEdge RAG Server (pgedge-rag-server)
- pgEdge RAG Server: < 2.0.0 (including 1.0.0, 1.0.0-beta1 through 1.0.0-beta3-test, and 1.0.0-alpha1 through 1.0.0-alpha5) (Fixed in:
2.0.0)
Code Analysis
Commit: a09d487
Isolate BM25 index instances per request in Orchestrator.search and bound FetchDocuments with bm25_max_documents.
--- a/internal/pipeline/orchestrator.go +++ b/internal/pipeline/orchestrator.go @@ -33,7 +33,6 @@ type Orchestrator struct { completionProv Completer reranker Reranker rerankTopK int - bm25Index *bm25.Index tokenBudget int topN int logger *slog.Logger @@ -66,7 +65,6 @@ func NewOrchestrator(cfg OrchestratorConfig) *Orchestrator { completionProv: cfg.CompletionProv, reranker: cfg.Reranker, rerankTopK: cfg.RerankTopK, - bm25Index: bm25.NewIndex(), tokenBudget: cfg.TokenBudget, topN: cfg.TopN, logger: logger, @@ -345,7 +348,7 @@ func (o *Orchestrator) search( continue } - docs, err := o.dbPool.FetchDocuments(ctx, table, req.Filter) + docs, err := o.dbPool.FetchDocuments(ctx, table, req.Filter, maxBM25Docs) if err != nil { o.logger.Warn("failed to fetch documents for BM25", "table", table.Table, "error", err) @@ -354,9 +357,28 @@ func (o *Orchestrator) search( continue } - o.bm25Index.Clear() - o.bm25Index.AddDocuments(docs) - bm25Results := o.bm25Index.Search(req.Query, topN*2) + if len(docs) >= maxBM25Docs { + o.logger.Warn( + "keyword search corpus truncated by bm25_max_documents; "+ + "keyword coverage for this request is partial", + "table", table.Table, "limit", maxBM25Docs, + ) + } + + index := bm25.NewIndex() + index.AddDocuments(docs) + bm25Results := index.Search(req.Query, topN*2) Exploit Details
- GitHub: Official concurrency regression test (TestSearch_ConcurrentRequestsDoNotShareKeywordIndex) demonstrating cross-tenant BM25 index leakage under concurrent load.
Mitigation Strategies
- Upgrade pgEdge RAG Server to version 2.0.0 or later to ensure BM25 indexes are instantiated per request rather than shared across the pipeline.
- Disable hybrid search (
hybrid_enabled: falseorvector_weight: 1.0) on pre-2.0.0 deployments to bypass the in-memory BM25 index entirely. - Disable raw source inclusion (
allow_include_sources: false) in pipeline configurations to prevent raw cross-tenant document snippets from being returned in API responses. - Place pgEdge RAG Server behind an authenticating reverse proxy or API gateway with rate limiting to prevent unauthenticated concurrent query floods.
Remediation Steps:
- Audit running processes and installed packages using
dpkg -l | grep pgedge-rag-server(Debian/Ubuntu) orrpm -qa | grep pgedge-rag-server(RHEL/CentOS) to identify version 1.x installations. - Install pgEdge RAG Server version 2.0.0 or later (
pgedge-rag-server2package or compiled binary from release tagv2.0.0). - Migrate pipeline configuration files to the v2.0.0 format and verify
search.bm25_max_documentsis set to a positive integer (default: 10000). - Stop and disable any legacy v1.0.0
pgedge-rag-serversystemd services listening on port 8080, and route all application traffic to the v2.0.0 service.
References
- GitHub Security Advisory GHSA-w437-9mwm-j6vq
- pgEdge RAG Server Pull Request #44
- Patch Commit a09d4872356b510c81f11591845445c33ff45a84
- pgEdge RAG Server Release v2.0.0
- NVD - CVE-2026-125325
- CVE.org Record - CVE-2026-125325
- CVE List V5 JSON Record - CVE-2026-125325
- pgEdge Security Documentation
Read the full report for CVE-2026-125325 on our website for more details including interactive diagrams and full exploit analysis.