FlawOpen

flawopen.com/Teardowns/langchain-mongodb-chat-history-query-injection-cve-2026-106119

● CVE-2026-106119 · CVSS v4 6.0[1] · Medium
FlawOpen Security Research

CVE-2026-106119: LangChain MongoDB Session Query Injection

CVE-2026-106119 affects @langchain/mongodb through 1.3.0 when untrusted session IDs reach MongoDBChatMessageHistory and multiple users share a collection. Upgrade to 1.3.1 or later.[1], [3]

CVSS vectorCVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N[1]
💡 Plain English Explainer (ELI5)

Imagine a librarian who expects a shelf label but accepts a whole instruction card in its place. The card can tell the filing desk to match more than one shelf, so a request meant for one reader may reach another reader’s history. The fix checks that the ID is a non-empty string and treats it only as a literal value.[1]

Core Concepts & Subsystem Terms

CVE-2026-106119
GitHub-reviewed advisory for query injection in MongoDBChatMessageHistory; fixed in @langchain/mongodb 1.3.1.[1]
Session identifier
The value used by MongoDBChatMessageHistory to select one conversation history. It must come from trusted, authenticated application context.[1]
MongoDB query operator
A structured key that changes how a filter matches documents. A value intended as a literal ID must not be accepted as an arbitrary query structure.[1]
CWE-943
Improper Neutralization of Special Elements in Data Query Logic; this is the weakness assigned by the advisory.[1], [4]

Framework mappings

  • CWE reference for the weakness described in this guide: CWE-943

Root Cause Analysis

The GitHub-reviewed advisory assigns CWE-943 and affects @langchain/mongodb versions through 1.3.0. MongoDBChatMessageHistory used sessionId directly as a MongoDB filter value without checking its runtime type. If an application forwards an untrusted request value and stores multiple users’ histories in one collection, a structured value can be interpreted as query logic rather than one session identifier. A caller able to invoke the history operation may then read, modify, or delete another user’s conversation. This is conditional on the application boundary and data-sharing setup; the advisory does not say every LangChain deployment is affected or that the issue is unauthenticated by default. The merged fix rejects values that are not non-empty strings and wraps the session ID in $eq for getMessages, addMessage, and clear. The advisory identifies 1.3.1 as fixed. Derive the identifier from authenticated server-side context, validate it at runtime, and upgrade; the explicit equality filter is defense in depth, not a substitute for identity authorization.[1], [2], [3]

Step-by-Step Attack Flow

Step 1

Untrusted input reaches the history boundary

An application is in scope only if it forwards an untrusted session value to the component and stores multiple users’ histories in one collection.[1]

Step 2

Runtime type is not enforced

The vulnerable constructor relied on TypeScript’s string type; that annotation does not validate values arriving at runtime.[1], [2]

Step 3

The value becomes filter logic

The history component used the value directly in MongoDB filters. A structured value could therefore alter which session documents match.[1], [2]

Step 4

Upgrade and bind the identity

Version 1.3.1 validates a non-empty string and uses $eq across history reads, writes, and deletion. Use a server-derived identity and test isolation between synthetic users.[1], [2]

Source Code: Flaw vs. Secure Implementation

These focused excerpts follow the upstream fix and affected query boundary; surrounding imports and class context are omitted, so they are not standalone programs or a proof of concept. TypeScript’s static string annotation does not validate a runtime value. The fix rejects non-string and empty identifiers before use, then wraps the value in MongoDB’s explicit equality operator. The upstream patch applies the $eq form to reads, appends, and deletion, not only this read path.[1], [2]

UNPATCHED FLAW
const document = await this.collection.findOne({
  [this.idKey]: this.sessionId,
});
HARDENED SECURE PATCH
if (typeof sessionId !== "string" || sessionId.length === 0) {
  throw new TypeError("sessionId must be a non-empty string");
}

const document = await this.collection.findOne({
  [this.idKey]: { $eq: this.sessionId },
});

Engineering & System Hardening Checklist

Sources