{"id":"CVE-2026-45288","aliases":["GHSA-vmw2-qwm8-x84c"],"url":"https://o3.security/vulnerability/CVE-2026-45288","summary":"Marten has an SQL injection vulnerability in its full-text search regConfig parameter","details":"## Summary\n\nMarten's full-text search APIs interpolated the user-supplied `regConfig` parameter directly into the generated SQL without parameterization or validation, making every code path that exposes `regConfig` to untrusted input a SQL injection sink.\n\n## Affected APIs\n\n- `IQuerySession.SearchAsync<T>(string searchTerm, string regConfig, ...)`\n- `IQuerySession.PlainTextSearchAsync<T>(...)`\n- `IQuerySession.PhraseSearchAsync<T>(...)`\n- `IQuerySession.WebStyleSearchAsync<T>(...)`\n- `IQuerySession.PrefixSearchAsync<T>(...)`\n- `IQueryable<T>.Where(x => x.Search(term, regConfig))` and the matching `PlainTextSearch` / `PhraseSearch` / `WebStyleSearch` / `PrefixSearch` extension methods\n\n## Details\n\nIn the affected versions, [`FullTextWhereFragment`](https://github.com/JasperFx/marten/blob/master/src/Marten/Linq/SqlGeneration/Filters/FullTextWhereFragment.cs) renders the WHERE-clause SQL by string interpolation:\n\n```csharp\nprivate string Sql =>\n    $\"to_tsvector('{_regConfig}'::regconfig, {_dataConfig}) @@ {_searchFunction}('{_regConfig}'::regconfig, ?)\";\n```\n\n`_regConfig` arrives unchanged from the public API surface above. Any value containing a single quote terminates the SQL literal and lets an attacker append arbitrary PostgreSQL.\n\n### Confirmed exploit shapes (with `regConfig` set to attacker-controlled input)\n\n| Goal | Payload |\n| --- | --- |\n| Time-based blind | `english'::text); SELECT pg_sleep(5); --` |\n| Information disclosure | `english'; SELECT version(); --` |\n| DDL execution | `english'; DROP TABLE mt_doc_article; --` |\n\nAll five overloads listed above produced SQL containing the verbatim payload.\n\n## Impact\n\n- **Confidentiality**: an attacker can append arbitrary `SELECT` statements and exfiltrate database contents through error channels, response timing, or — if the application surfaces query results — directly.\n- **Integrity / Availability**: DDL, `UPDATE`, `DELETE`, and `pg_sleep`-style denial-of-service payloads succeed under the same vector. Concrete impact depends on the database role used by the Marten connection string.\n- **Precondition**: the calling application must forward attacker-controlled input into the `regConfig` parameter (e.g. a `?lang=` query string mapped to `regConfig`). Applications that hard-code `regConfig` to a compile-time constant are not exploitable.\n\n## Patches\n\nFixed in **Marten 8.36.1** (and forward) by [#4343](https://github.com/JasperFx/marten/pull/4343).\n\n`FullTextWhereFragment` now validates `regConfig` against `^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)?$` (a simple PostgreSQL identifier, optionally schema-qualified, capped at `NAMEDATALEN-1` per side) and throws `ArgumentException` for anything else. The default value (`\"english\"`), schema-qualified configs (`\"pg_catalog.english\"`), and the standard PostgreSQL text-search configurations all continue to work.\n\n## Workarounds\n\nIf users cannot upgrade immediately, do **one** of the following at the application boundary:\n\n1. Hard-code `regConfig` to a compile-time constant (`\"english\"`, `\"simple\"`, …) and never accept it from request input.\n2. Validate any externally-sourced `regConfig` value before passing it to Marten — e.g. against the same regex as the patch (`^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)?$`) or against an allowlist of PostgreSQL configurations the application actually uses.\n3. Drop the `regConfig` argument from the call site so Marten falls back to the safe default.\n\n## Resources\n\n- Patch PR: [JasperFx/marten#4343](https://github.com/JasperFx/marten/pull/4343)\n- Patched file: [`FullTextWhereFragment.cs`](https://github.com/JasperFx/marten/blob/master/src/Marten/Linq/SqlGeneration/Filters/FullTextWhereFragment.cs)\n- Regression tests: [`full_text_regconfig_sql_injection.cs`](https://github.com/JasperFx/marten/blob/master/src/LinqTests/Bugs/full_text_regconfig_sql_injection.cs)\n- CWE-89: <https://cwe.mitre.org/data/definitions/89.html>\n\n## Credit\n\nReported privately to the JasperFx team with a working proof of concept covering all five affected overloads.","published":"2026-05-28T20:20:11.377Z","modified":"2026-08-12T03:51:15.802269985Z","cvss":{"score":9.8,"severity":"CRITICAL","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"},"epss":{"score":0.00375,"percentile":0.30651,"asOf":"2026-08-16"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"NuGet","name":"Marten","fixedVersion":"8.37.0"}],"fix":{"url":"https://github.com/JasperFx/marten/commit/626249656829860b9c55895b5b6046b61a2a695f","label":"JasperFx/marten@6262496"},"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/45xxx/CVE-2026-45288.json"},{"type":"ADVISORY","url":"https://github.com/JasperFx/marten/security/advisories/GHSA-vmw2-qwm8-x84c"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-45288"},{"type":"FIX","url":"https://github.com/JasperFx/marten/commit/626249656829860b9c55895b5b6046b61a2a695f"},{"type":"FIX","url":"https://github.com/JasperFx/marten/pull/4343"},{"type":"PACKAGE","url":"https://github.com/JasperFx/marten"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:15.802269985Z"}}