{"id":"CVE-2026-55405","title":"LangChain4j: SQL injection via metadata filters in langchain4j-mariadb and langchain4j-pgvector","summary":"LangChain4j: SQL injection via metadata filters in langchain4j-mariadb and langchain4j-pgvector","severity":"high","cvss":7.6,"cwe":["CWE-89"],"vendor":"langchain4j","product":"dev.langchain4j:langchain4j-mariadb","ecosystem":"maven","affected":["dev.langchain4j:langchain4j-mariadb <= 1.2.0-beta8","dev.langchain4j:langchain4j-mariadb >= 1.3.0-beta9, <= 1.5.0-beta11","dev.langchain4j:langchain4j-mariadb >= 1.6.0-beta12, <= 1.11.7-beta19","dev.langchain4j:langchain4j-mariadb >= 1.12.1-beta21, <= 1.16.2-beta26","dev.langchain4j:langchain4j-pgvector <= 1.2.0-beta8","dev.langchain4j:langchain4j-pgvector >= 1.3.0-beta9, <= 1.5.0-beta11","dev.langchain4j:langchain4j-pgvector >= 1.6.0-beta12, <= 1.11.7-beta19","dev.langchain4j:langchain4j-pgvector >= 1.12.1-beta21, <= 1.16.2-beta26"],"patched":["dev.langchain4j:langchain4j-mariadb 1.2.1-beta8","dev.langchain4j:langchain4j-mariadb 1.5.1-beta11","dev.langchain4j:langchain4j-mariadb 1.11.8-beta19","dev.langchain4j:langchain4j-mariadb 1.16.3-beta26","dev.langchain4j:langchain4j-pgvector 1.2.1-beta8","dev.langchain4j:langchain4j-pgvector 1.5.1-beta11","dev.langchain4j:langchain4j-pgvector 1.11.8-beta19","dev.langchain4j:langchain4j-pgvector 1.16.3-beta26"],"published":"2026-06-17","updated":"2026-06-17","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-2mfg-cc43-9pcj","references":[{"url":"https://github.com/langchain4j/langchain4j/security/advisories/GHSA-2mfg-cc43-9pcj"},{"url":"https://github.com/advisories/GHSA-2mfg-cc43-9pcj"}],"tags":["ghsa","maven"],"ingestedAt":"2026-06-29T14:31:47.190Z","epss":0.00474,"epssPercentile":0.4019,"slug":"CVE-2026-55405","body":"## Overview\n\n### Summary\nThe MariaDB and pgvector embedding stores build metadata-filter SQL by string-concatenating\nfilter **keys** (and, in MariaDB, string **values**) directly into the query without adequate\nescaping. A crafted metadata key in `EmbeddingSearchRequest.filter()` can break out of its SQL\ncontext and inject arbitrary SQL into the statements executed by the stores' search and\n`removeAll(Filter)` operations.\n\n### Details\n**pgvector — JSON mode (default, `COMBINED_JSON` / `COMBINED_JSONB`).** `JSONFilterMapper`\nplaces the key inside a single-quoted SQL literal (the JSON key of the `->>` operator) with no\nescaping:\n\n    (metadata->>'<key>')::text\n\nA key containing a single quote breaks out, e.g.\n`metadataKey(\"')::text IS NOT NULL OR pg_sleep(1) IS NOT NULL --\")` injects a live `pg_sleep(1)`\n(observable as a delay; exploitable for blind data extraction).\n\n**pgvector — column mode (`COLUMN_PER_KEY`).** `ColumnFilterMapper` used the key as a bare,\nunquoted, unvalidated SQL identifier (`<key>::<type>`), so a key such as `1=1 OR true --`\ninjects directly.\n\n**MariaDB — JSON mode (default).** `JSONFilterMapper` placed the key inside the JSON path literal\n`'$.<key>'` unescaped (same break-out mechanism). Additionally, `MariaDbFilterMapper.formatValue()`\nescaped `'` but not `\\`; because MariaDB treats backslash as an escape character by default, a\nstring value ending in a backslash could also break out of its literal.\n\n**MariaDB — column mode (`COLUMN_PER_KEY`).** `ColumnFilterMapper` fell back to the raw,\nunescaped key when the driver could not quote it as an identifier (e.g. a\ncharacter).\n\nThe filter key is the runtime injection surface; both stores' `search()` (including pgvector's\nHYBRID mode) and `removeAll(Filter)` are affected. Add/upsert operations a\nparameterized and not affected.\n\n### Impact\nApplications that allow attacker-influenced metadata filter keys (e.g. use\nLLM-generated filters) to reach these stores are exposed to SQL injection: blind data\nexfiltration, denial of service via sleep functions, and — through `remove\ndeletion of arbitrary rows. Applications using only hard-coded, developer-defined filter keys\nare not reachable.\n\n### Patches\nFixed in `langchain4j-mariadb` and `langchain4j-pgvector` 1.16.3-beta26:\n- JSON filter keys are escaped before being embedded in the SQL string lit\n  quotes doubled, correct for PostgreSQL `standard_conforming_strings = on`; MariaDB: backslash\n  and single quote).\n- MariaDB string values escape both `\\` and `'`.\n- Column-mode keys are validated/quoted as identifiers and rejected when u\n  concatenated as raw SQL.\n\n### Workarounds\n- Do not pass untrusted input as metadata filter keys.\n- Restrict filter keys to a known allow-list at the application layer.\n\n### References\n- pgvector: `JSONFilterMapper`, `ColumnFilterMapper`\n- MariaDB: `JSONFilterMapper`, `MariaDbFilterMapper`, `ColumnFilterMapper`\n\n## Affected packages\n\n- `dev.langchain4j:langchain4j-mariadb <= 1.2.0-beta8`\n- `dev.langchain4j:langchain4j-mariadb >= 1.3.0-beta9, <= 1.5.0-beta11`\n- `dev.langchain4j:langchain4j-mariadb >= 1.6.0-beta12, <= 1.11.7-beta19`\n- `dev.langchain4j:langchain4j-mariadb >= 1.12.1-beta21, <= 1.16.2-beta26`\n- `dev.langchain4j:langchain4j-pgvector <= 1.2.0-beta8`\n- `dev.langchain4j:langchain4j-pgvector >= 1.3.0-beta9, <= 1.5.0-beta11`\n- `dev.langchain4j:langchain4j-pgvector >= 1.6.0-beta12, <= 1.11.7-beta19`\n- `dev.langchain4j:langchain4j-pgvector >= 1.12.1-beta21, <= 1.16.2-beta26`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `dev.langchain4j:langchain4j-mariadb 1.2.1-beta8`\n- `dev.langchain4j:langchain4j-mariadb 1.5.1-beta11`\n- `dev.langchain4j:langchain4j-mariadb 1.11.8-beta19`\n- `dev.langchain4j:langchain4j-mariadb 1.16.3-beta26`\n- `dev.langchain4j:langchain4j-pgvector 1.2.1-beta8`\n- `dev.langchain4j:langchain4j-pgvector 1.5.1-beta11`\n- `dev.langchain4j:langchain4j-pgvector 1.11.8-beta19`\n- `dev.langchain4j:langchain4j-pgvector 1.16.3-beta26`","depth":"twilight","depthScore":42,"depthScoreParts":{"impact":41.8,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}