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…

Detection rules are retrieved from Rulezet.

Loading…

Loading…