---
id: "CVE-2026-75513"
page: "https://infrastack.ai/live/CVE-2026-75513"
kind: "vulnerability"
aliases: ["CVE-2026-75513", "GHSA-rfx3-98h7-v3xp"]
title: "Marten's LINQ provider has SQL injection via unescaped string literals"
severity: "critical"
cvss: 9.1
epss: 0.00468
exploited: false
status: "open"
category: "package"
products: [{"name": "Marten", "fixed": ["8.37.4"], "affected": ">= 7.0.0, < 8.37.4", "ecosystem": "nuget"}, {"name": "Marten", "fixed": ["9.13.0"], "affected": ">= 9.0.0, < 9.13.0", "ecosystem": "nuget"}]
ecosystems: ["nuget"]
tags: ["cwe-89", "dotnet", "marten", "multi-tenant", "nuget", "package", "postgresql"]
not_affected_if: ["no-user-controlled-keys", "static-query-values", "versions-patched"]
published_at: "2026-09-16T21:17:13+00:00"
first_seen_at: "2026-11-09T16:41:12+00:00"
updated_at: "2026-11-09T16:57:34+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-rfx3-98h7-v3xp", "first_seen_at": "2026-11-09T16:41:12+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-75513", "first_seen_at": "2026-11-09T16:57:34+00:00"}]
exploit_sources: [{"type": "epss", "score": 0.00468, "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-75513"}]
---

# Marten's LINQ provider has SQL injection via unescaped string literals

Link for people: https://infrastack.ai/live/CVE-2026-75513 (this .md is for agents)

Marten's LINQ provider pasted some runtime values, such as a dictionary indexer key used in a Where filter, into generated SQL inside single-quoted literals without escaping. A value containing a single quote can break out of the literal and run arbitrary SQL, which allows reading or changing other tenants' rows.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- nuget:Marten affected >= 7.0.0, < 8.37.4 fixed 8.37.4
- nuget:Marten affected >= 9.0.0, < 9.13.0 fixed 9.13.0

## How to check

- Look for the `Marten` NuGet package in your project files (`*.csproj`, `packages.lock.json`) and note its version.
- Search your code for LINQ `Where` filters that index a `Dictionary` with a value taken from user input, and for `ContainsKey` calls on such input.
- Check whether tenant ids or projection names come from request data.

## Fix

- `Marten` `8.37.4` for the 8.x line (affected from `7.0.0` up to but not including `8.37.4`)
- `Marten` `9.13.0` for the 9.x line (affected from `9.0.0` up to but not including `9.13.0`)

## Timeline

- 2026-11-09T16:41:12+00:00 ghsa https://github.com/advisories/GHSA-rfx3-98h7-v3xp
- 2026-11-09T16:57:34+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-75513

## Documents

- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/JasperFx/marten/security-advisories/GHSA-rfx3-98h7-v3xp
- [advisory] Maintainer's advisory: github.com https://github.com/JasperFx/marten/security/advisories/GHSA-rfx3-98h7-v3xp
- [fix] Patch: github.com https://github.com/JasperFx/marten/pull/4911
- [fix] Patch: github.com https://github.com/JasperFx/marten/commit/61882d0424854cb48703f08bdb246894ac576bed
- [fix] Release: github.com https://github.com/JasperFx/marten/releases/tag/9.13.0
- [fix] Release: github.com https://github.com/JasperFx/marten/releases/tag/8.37.4

## From the sources

Several code paths in Marten's LINQ provider and tenant-management internals interpolated a runtime, potentially attacker-influenced value into generated SQL as a single-quoted string literal without escaping or parameterization. A value containing a single quote (`'`) could break out of the literal and inject arbitrary SQL.

The primary vector is a `Dictionary<,>` indexer **key** used in a `Where` filter — `Where(x => x.Attributes[key] == v)` — a common "filter by attribute name" / EAV pattern. It is confirmed with an executed proof-of-concept and yields filter / multi-tenant authorization bypass (returning other tenants' rows) and blind data exfiltration. Where the application permits `;`-batched statements (Npgsql default), data modification is also possible.

## Affected sinks

- `Linq/Members/Dictionaries/DictionaryItemMember.cs` — dictionary indexer key (primary, confirmed PoC)
- `Linq/Members/Dictionaries/DictionaryContainsKeyFilter.cs` — `Dictionary.ContainsKey(key)` (Newtonsoft serializer only; System.Text.Json escapes the quote)
- `Linq/Parsing/SelectParser.cs` — a constant string projected through `Select(x => new { L = runtimeString })`
- `Internal/Operations/DeleteAllForTenant.cs` — tenant id reaching per-tenant projection teardown via `IEventStore.DeleteProjectionProgressAsync` (an in-code comment wrongly claimed the value was validated)
- `Schema/DatabaseScopedTenantPartitions.cs` — tenant id inlined into `FOR VALUES IN ('...')` partition DDL
- `Events/Daemon/Internals/EventLoader.cs` (defense-in-depth) — per-tenant partition-pruning literal

## Proof of concept (primary vector)

Benign: `x.Attributes["nonexistent-key"] == "v"` returns 0 rows. Attack: `x.Attributes["nonexistent' = '' or 1=1 --"] == "v"` returns all rows. Generated SQL:

```
select d.data from public.mt_doc_doc as d where d.data -> 'Attributes' ->> 'x' or 1=1 --' = :p0;
```

## Fix

Each sink now escapes embedded single quotes (`.Replace("'", "''")`, mirroring the existing `Ordering.BuildNgramRankExpression`) or binds the value as a parameter (`DeleteAllForTenant`). Where a literal is retained for partition pruning, escaping preserves plan-time pruning while closing the injection. Regression tests lock down each vector.

## Workarounds

Until upgrading: do not pass untrusted input as a dictionary indexer key / `ContainsKey` argument / `Select` constant, nor as a tenant id into projection teardown or provisioning; and disable multi-statement command batching to limit blast radius.

## Credit

Reported privately and responsibly by an external security researcher with an executed PoC. Additional sinks found during the follow-up LINQ-wide audit.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
