GHSA-2MFG-CC43-9PCJ

Vulnerability from github – Published: 2026-06-17 18:39 – Updated: 2026-06-17 18:39
VLAI
Summary
LangChain4j: SQL injection via metadata filters in langchain4j-mariadb and langchain4j-pgvector
Details

Summary

The MariaDB and pgvector embedding stores build metadata-filter SQL by string-concatenating filter keys (and, in MariaDB, string values) directly into the query without adequate escaping. A crafted metadata key in EmbeddingSearchRequest.filter() can break out of its SQL context and inject arbitrary SQL into the statements executed by the stores' search and removeAll(Filter) operations.

Details

pgvector — JSON mode (default, COMBINED_JSON / COMBINED_JSONB). JSONFilterMapper places the key inside a single-quoted SQL literal (the JSON key of the ->> operator) with no escaping:

(metadata->>'<key>')::text

A key containing a single quote breaks out, e.g. metadataKey("')::text IS NOT NULL OR pg_sleep(1) IS NOT NULL --") injects a live pg_sleep(1) (observable as a delay; exploitable for blind data extraction).

pgvector — column mode (COLUMN_PER_KEY). ColumnFilterMapper used the key as a bare, unquoted, unvalidated SQL identifier (<key>::<type>), so a key such as 1=1 OR true -- injects directly.

MariaDB — JSON mode (default). JSONFilterMapper placed the key inside the JSON path literal '$.<key>' unescaped (same break-out mechanism). Additionally, MariaDbFilterMapper.formatValue() escaped ' but not \; because MariaDB treats backslash as an escape character by default, a string value ending in a backslash could also break out of its literal.

MariaDB — column mode (COLUMN_PER_KEY). ColumnFilterMapper fell back to the raw, unescaped key when the driver could not quote it as an identifier (e.g. a character).

The filter key is the runtime injection surface; both stores' search() (including pgvector's HYBRID mode) and removeAll(Filter) are affected. Add/upsert operations a parameterized and not affected.

Impact

Applications that allow attacker-influenced metadata filter keys (e.g. use LLM-generated filters) to reach these stores are exposed to SQL injection: blind data exfiltration, denial of service via sleep functions, and — through `remove deletion of arbitrary rows. Applications using only hard-coded, developer-defined filter keys are not reachable.

Patches

Fixed in langchain4j-mariadb and langchain4j-pgvector 1.16.3-beta26: - JSON filter keys are escaped before being embedded in the SQL string lit quotes doubled, correct for PostgreSQL standard_conforming_strings = on; MariaDB: backslash and single quote). - MariaDB string values escape both \ and '. - Column-mode keys are validated/quoted as identifiers and rejected when u concatenated as raw SQL.

Workarounds

  • Do not pass untrusted input as metadata filter keys.
  • Restrict filter keys to a known allow-list at the application layer.

References

  • pgvector: JSONFilterMapper, ColumnFilterMapper
  • MariaDB: JSONFilterMapper, MariaDbFilterMapper, ColumnFilterMapper
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.2.0-beta8"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "dev.langchain4j:langchain4j-mariadb"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.2.1-beta8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.5.0-beta11"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "dev.langchain4j:langchain4j-mariadb"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.3.0-beta9"
            },
            {
              "fixed": "1.5.1-beta11"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.11.7-beta19"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "dev.langchain4j:langchain4j-mariadb"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.6.0-beta12"
            },
            {
              "fixed": "1.11.8-beta19"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.16.2-beta26"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "dev.langchain4j:langchain4j-mariadb"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.12.1-beta21"
            },
            {
              "fixed": "1.16.3-beta26"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.2.0-beta8"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "dev.langchain4j:langchain4j-pgvector"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.2.1-beta8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.5.0-beta11"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "dev.langchain4j:langchain4j-pgvector"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.3.0-beta9"
            },
            {
              "fixed": "1.5.1-beta11"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.11.7-beta19"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "dev.langchain4j:langchain4j-pgvector"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.6.0-beta12"
            },
            {
              "fixed": "1.11.8-beta19"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.16.2-beta26"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "dev.langchain4j:langchain4j-pgvector"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.12.1-beta21"
            },
            {
              "fixed": "1.16.3-beta26"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55405"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-89"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-17T18:39:56Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### 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\u0027 search and\n`removeAll(Filter)` operations.\n\n### Details\n**pgvector \u2014 JSON mode (default, `COMBINED_JSON` / `COMBINED_JSONB`).** `JSONFilterMapper`\nplaces the key inside a single-quoted SQL literal (the JSON key of the `-\u003e\u003e` operator) with no\nescaping:\n\n    (metadata-\u003e\u003e\u0027\u003ckey\u003e\u0027)::text\n\nA key containing a single quote breaks out, e.g.\n`metadataKey(\"\u0027)::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 \u2014 column mode (`COLUMN_PER_KEY`).** `ColumnFilterMapper` used the key as a bare,\nunquoted, unvalidated SQL identifier (`\u003ckey\u003e::\u003ctype\u003e`), so a key such as `1=1 OR true --`\ninjects directly.\n\n**MariaDB \u2014 JSON mode (default).** `JSONFilterMapper` placed the key inside the JSON path literal\n`\u0027$.\u003ckey\u003e\u0027` unescaped (same break-out mechanism). Additionally, `MariaDbFilterMapper.formatValue()`\nescaped `\u0027` 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 \u2014 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\u0027 `search()` (including pgvector\u0027s\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 \u2014 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 `\u0027`.\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`",
  "id": "GHSA-2mfg-cc43-9pcj",
  "modified": "2026-06-17T18:39:56Z",
  "published": "2026-06-17T18:39:56Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/langchain4j/langchain4j/security/advisories/GHSA-2mfg-cc43-9pcj"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/langchain4j/langchain4j"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "LangChain4j: SQL injection via metadata filters in langchain4j-mariadb and langchain4j-pgvector"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…