Vulnerabilities in pkg:pypi/mercury

PACKAGE
Advisory Identifier: GHSA-2658-85cv-9wwq
Advisory Summary

CVE-2026-111059 is a MODERATE (CVSS 6.1) cross-site scripting vulnerability (CWE-116: Improper Encoding or Escaping of Output) affecting Mercury libraries in the PyPI ecosystem. The issue involves stored / dom cross-site scripting (xss): mr.markdown renders untrusted content as raw, unsanitized html. Remediation is available by upgrading affected packages to version 3.2.11.

3 Known Advisory Record(s)
Package Vulnerability Intelligence

pkg:pypi/mercury

3 Known Advisory Record(s)

Vulnerability advisories affecting package pkg:pypi/mercury. Select an advisory below to view technical details or fixes.

Advisory ID CVE / NVD Severity Summary
GHSA-2658-85cv-9wwq CVE-2026-111059 MODERATE Mercury: Stored / DOM Cross-Site Scripting (XSS): mr.Markdown renders untrusted content as raw, unsanitized HTML
GHSA-f8c7-rwf9-fmgm CVE-2026-111057 CRITICAL Mercury: Unauthenticated Remote Code Execution in /api/terminals - access control bypass
GHSA-rv4m-xm3f-3ccq CVE-2026-111058 CRITICAL Mercury: Unauthenticated Remote Code Execution via /api/kernels

CVE-2026-111059 at a Glance

CVE Identifier CVE-2026-111059
GHSA Identifier GHSA-2658-85cv-9wwq
Severity MODERATE
CVSS v3.1 Base Score 6.1
CWE Classification CWE-116: Improper Encoding or Escaping of Output
Affected Product Mercury
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 6.1

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction Required (UI:R)
Scope Changed (S:C)
Confidentiality Low (C:L)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-111059

To remediate this vulnerability, upgrade all affected Mercury dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

mercury fixed: 3.2.11
pip install mercury>=3.2.11
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show mercury

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-111059, inspect your installed packages using pip:

pip show mercury

Analyze the terminal output to locate any version of Mercury in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.2.11), your application is affected.

Note: The pip show mercury command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-116: Improper Encoding or Escaping of Output, where the product prepares a structured message for communication with another component, but encoding or escaping of the data is either missing or done incorrectly. as a result, the intended structure of the message is not preserved. In Mercury, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary Mercury turns Jupyter notebooks into shared web apps/dashboards. The `mr.Markdown` widget converts its input to HTML with **python-markdown and no sanitization step**. `MarkdownWidget` is an `ipywidgets.HTML` widget, whose value is written to the page as **raw HTML (via `innerHTML`) with no sanitization**, so the result reaches the DOM verbatim. When an app passes **untrusted data** (database rows, user submissions, uploaded file contents, or an external/LLM API response) to `mr.Markdown`, HTML/JS in that data executes in the browser of **whoever views the app** — a data-driven stored/DOM-based XSS. This is a library-provided rendering sink that fails to neutralize output; it is triggered by ordinary, reasonable application code, not by an author mistake. ## Root cause `mercury/md.py` — `MarkdownWidget._to_html()` (verified at v3.2.6, lines ~57–65): ```python def _to_html(self, text: str) -> str: if md_lib is not None: body = md_lib.markdown(text) # python-markdown: passes raw HTML through else: body = f"<pre>{escape(text)}</pre>" # escape() is ONLY the md-lib-absent fallback return self._apply_inline_theme(body) # regex styling — adds style=, removes nothing ``` Two neutralization failures compound: 1. **Markdown → HTML is unsanitized.** `python-markdown` passes raw HTML through by default: `<img src=x onerror=…>`, `<svg onload=…>`, and `javascript:` links survive verbatim. There is no `bleach`/`nh3` allowlist anywhere in the package. `_apply_inline_theme()` only injects inline `style=` attributes via regex; it is not a sanitizer and removes nothing. `escape()` runs only in the md-lib-absent fallback. 2. **The rendering sink is unsanitized `innerHTML`.** `MarkdownWidget` (`mercury/md.py:21`) subclasses `ipywidgets.HTML`. The ipywidgets HTML widget renders its `value` into the DOM as raw HTML via `innerHTML`, with no sanitization (this is the widget's design). Event-handler payloads such as `<img src=x onerror=…>` therefore execute when the widget is displayed. **On the "sanitize" that exists:** `mercury_app/notebook_sanitize.py` (`sanitize_notebook_for_mercury_runtime`) and `packages/lab/src/mercury/save.ts` (`sanitizeMercuryNotebookContent`) strip *runtime metadata* and clear *code-cell saved outputs*. They do **not** neutralize HTML/JS, and they do not touch widget values or markdown source. "Sanitize" here is notebook hygiene, not XSS defense. ## Threat model (attacker → victim, not self-inflicted) The CVE-relevant framing is **data-driven**: the app author writes ordinary code, and the *data* is attacker-controlled. ```python import mercury as mr # `row` comes from a DB / user submission / uploaded file / external API — # i.e. NOT authored by the app developer: mr.Markdown(row["comment"]) ``` The attacker supplies the untrusted value (posts the comment, uploads the file, poisons the API/RAG source). A **different** user — another app user, a reviewer, an admin — then opens the app, and the payload executes in *their* browser. The vulnerable component (Mercury's server-side widget rendering) and the impacted component (the victim's browser session in the app origin) differ, which is the classic stored-XSS attacker/victim separation. **Amplifier — session sharing (`--keep-session`).** Mercury can serve one shared kernel session to all viewers (`mercury run … --keep-session`, README "Arguments": "share the same session between multiple users … others will see this"). It is **opt-in and defaults to off** (`keepSession=False` in `mercury_app/handlers.py`), so it is *not required* for the base case — any app that renders one user's untrusted data to another user is already vulnerable. When enabled, content one viewer submits is rendered into the session other viewers see, extending this to cross-user delivery. Authentication is **opt-in and off by default**: a free password gate exists (`mercury run … --pass=…`, README), while user-based authentication is a paid add-on. Because auth is off unless the operator enables it, unauthenticated public deployments — where the attacker needs no account — are a realistic default. ## Proof of Concept ```python import mercury as mr # Value that would realistically arrive from untrusted data (DB row, form field, # uploaded file, API/LLM response): untrusted = '<img src=x onerror=alert(String.fromCharCode(88,83,83))>' mr.Markdown(untrusted) # rendered to raw HTML, unsanitized, into the app DOM ``` The generated widget HTML contains the payload verbatim; when the widget is displayed, the `onerror` handler runs. ### What was confirmed (and how) - **Confirmed by execution in a real browser (sink level):** driving the *actual `python-markdown` output* into the same `ipywidgets.HTML` `value` sink the widget uses causes the payload to execute in headless Chromium. Execution was captured via Playwright's `dialog` event (which fires only on a genuine `alert()`, so the mere presence of the string in the HTML cannot cause a false positive). A benign control (`**hello**`) produced **zero** dialogs, confirming the harness reports only real execution. `python-markdown` passes `<img src=x onerror=…>` through verbatim by default (behavior is not version-specific). - **Reasoned from source (not executed end-to-end):** the full path from a `mr.Markdown(...)` call in a *served Mercury app* to a viewer's DOM was not run end-to-end, because no isolated container/VM was available in the reporting environment. Because `MarkdownWidget` *is* the `ipywidgets.HTML` sink above and Mercury's frontend applies no sanitizer to widget HTML values (the only frontend sanitizer strips notebook metadata at save time), the served-app path is expected to behave identically. Reproduce end-to-end before publishing if you want the advisory to state full-path browser confirmation. ## Impact Mercury shares notebooks as web apps/dashboards, often for non-technical audiences. When an app renders untrusted data through `mr.Markdown`, the generated page carries attacker-controlled script that runs in the browser of any other viewer, in the app origin — enabling session/cookie/token theft, UI spoofing and forced actions as the victim, and pivoting within the hosting origin. With `--keep-session`, this extends to cross-user delivery within a shared session. ## Severity rationale (CVSS 3.1 per-metric) Base score reflects the realistic default: an unauthenticated deployment whose app renders untrusted data via `mr.Markdown`. | Metric | Value | Reason | |---|---|---| | **AV** Attack Vector | **Network (N)** | App is served over HTTP to remote users. | | **AC** Attack Complexity | **Low (L)** | No special conditions or race; supply data that reaches an `mr.Markdown` call. | | **PR** Privileges Required | **None (N)** | Baseline: the injection channel (public form/upload/API) needs no account; auth is optional/paid. See variant below. | | **UI** User Interaction | **Required (R)** | A victim must open/view the app page for the stored payload to run. | | **S** Scope | **Changed (C)** | The vulnerable component (server-side widget render) injects script that executes in a different security authority — the victim's browser session/origin. (This is the canonical XSS scoping in the CVSS 3.1 spec.) | | **C** Confidentiality | **Low (L)** | Script can read data/session material available to the app origin; scored L (not H) for a generic app without asserting full account takeover. | | **I** Integrity | **Low (L)** | Script can alter the page and act as the victim within the app; scored L generically. | | **A** Availability | **None (N)** | No direct availability impact. | Result: **`CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N` = 6.1 (Medium)**. Deployment-dependent variants (state your environment's when filing): - Injection channel requires an authenticated low-privilege user → **PR:L** → `…/PR:L/UI:R/S:C/C:L/I:L/A:N` = **5.4**. - App origin exposes high-value auth material such that XSS yields full session/account takeover → **C:H/I:H** raises the score; justify per deployment rather than claiming it universally. ## Remediation Primary — **sanitize by default in `mr.Markdown`, with an explicit opt-out for the deliberate raw-HTML use case** (backward-compatible, non-breaking): ```python # mercury/md.py def _to_html(self, text: str, unsafe_allow_html: bool = False) -> str: if md_lib is not None: body = md_lib.markdown(text) else: body = f"<pre>{escape(text)}</pre>" if not unsafe_allow_html: # allowlist tags/attributes; strip javascript:/data: schemes and event handlers body = nh3.clean(body) # or bleach.clean(..., strip=True) return self._apply_inline_theme(body) ``` Expose `unsafe_allow_html=False` on `mr.Markdown(...)` so authors who deliberately embed trusted raw HTML can opt in, while the default is safe. This mirrors the convention used by comparable tools (e.g. Streamlit's `unsafe_allow_html`). Defense-in-depth: since widget HTML values are written via `innerHTML` without sanitization, consider sanitizing widget HTML values at the frontend before they reach the DOM, and/or serving a Content-Security-Policy that forbids inline event handlers, so a single missed sink is not immediately exploitable. ## Additional hardening (secondary — not the reported vulnerability) Several widget ESMs write the **label** with `innerHTML`, e.g. `mercury/text.py` `topLabel.innerHTML = model.get("label") || …` (same shape in `number.py`, `time.py`, `date`/`datetime`/`daterange`/`select`/`json`/`file`, and `indicator.py`'s `_card_html`). **This is not an attacker→victim XSS path**: labels are static strings set by the app author in Python; URL/`url_params` overrides affect only widget `value` (assigned via the safe `input.value` property), never `label`, so there is no end-user/URL route into a label. It is a defense-in-depth / author footgun only. Recommended regardless: render UI strings with `textContent`, or `html.escape` labels, so output encoding is applied uniformly.

CVE-2026-111059 Affected Mercury Versions

1 component(s)
Fixed Versions:
3.2.11
Product / Package Ecosystem Affected Versions Fixed Version
mercury
PyPI
≥ 3.0.0
< 3.2.11
3.2.11

References

Frequently Asked Questions

What is CVE-2026-111059?
CVE-2026-111059 is a security vulnerability in Mercury involving Stored / DOM Cross-Site Scripting (XSS): mr.Markdown renders untrusted content as raw, unsanitized HTML under CWE-116: Improper Encoding or Escaping of Output.
Which Mercury versions are affected?
Affected versions include releases prior to 3.2.11 across affected packages: mercury.
What version fixes CVE-2026-111059?
Upgrading to 3.2.11 (or the latest patched release for your respective branch) resolves the vulnerability.
Is mercury affected?
Yes, mercury is affected in releases prior to 3.2.11. Upgrade your dependency to 3.2.11 or later.
What is the CVSS score of CVE-2026-111059?
CVE-2026-111059 has a CVSS v3.1 base score of 6.1 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N.
What CWE is associated with CVE-2026-111059?
CVE-2026-111059 is classified under CWE-116: Improper Encoding or Escaping of Output (The product prepares a structured message for communication with another component, but encoding or escaping of the data is either missing or done incorrectly. As a result, the intended structure of the message is not preserved.).
How can I check PyPI dependencies for CVE-2026-111059?
Run the dependency tree command: 'pip show mercury'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-2658-85cv-9wwq",
  "modified" : "2026-10-19T17:01:20Z",
  "published" : "2026-10-19T17:01:20Z",
  "aliases" : [ "CVE-2026-111059" ],
  "summary" : "Mercury: Stored / DOM Cross-Site Scripting (XSS): mr.Markdown renders untrusted content as raw, unsanitized HTML",
  "details" : "## Summary\n\nMercury turns Jupyter notebooks into shared web apps/dashboards. The `mr.Markdown`\nwidget converts its input to HTML with **python-markdown and no sanitization\nstep**. `MarkdownWidget` is an `ipywidgets.HTML` widget, whose value is written to\nthe page as **raw HTML (via `innerHTML`) with no sanitization**, so the result\nreaches the DOM verbatim. When an app passes **untrusted data** (database rows,\nuser submissions, uploaded file contents, or an external/LLM API response) to\n`mr.Markdown`, HTML/JS in that data executes in the browser of **whoever views the\napp** — a data-driven stored/DOM-based XSS.\n\nThis is a library-provided rendering sink that fails to neutralize output; it is\ntriggered by ordinary, reasonable application code, not by an author mistake.\n\n## Root cause\n\n`mercury/md.py` — `MarkdownWidget._to_html()` (verified at v3.2.6, lines ~57–65):\n\n```python\ndef _to_html(self, text: str) -> str:\n    if md_lib is not None:\n        body = md_lib.markdown(text)          # python-markdown: passes raw HTML through\n    else:\n        body = f\"<pre>{escape(text)}</pre>\"   # escape() is ONLY the md-lib-absent fallback\n    return self._apply_inline_theme(body)     # regex styling — adds style=, removes nothing\n```\n\nTwo neutralization failures compound:\n\n1. **Markdown → HTML is unsanitized.** `python-markdown` passes raw HTML through by\n   default: `<img src=x onerror=…>`, `<svg onload=…>`, and `javascript:` links\n   survive verbatim. There is no `bleach`/`nh3` allowlist anywhere in the package.\n   `_apply_inline_theme()` only injects inline `style=` attributes via regex; it is\n   not a sanitizer and removes nothing. `escape()` runs only in the\n   md-lib-absent fallback.\n\n2. **The rendering sink is unsanitized `innerHTML`.** `MarkdownWidget`\n   (`mercury/md.py:21`) subclasses `ipywidgets.HTML`. The ipywidgets HTML widget\n   renders its `value` into the DOM as raw HTML via `innerHTML`, with no\n   sanitization (this is the widget's design). Event-handler payloads such as\n   `<img src=x onerror=…>` therefore execute when the widget is displayed.\n\n**On the \"sanitize\" that exists:** `mercury_app/notebook_sanitize.py`\n(`sanitize_notebook_for_mercury_runtime`) and `packages/lab/src/mercury/save.ts`\n(`sanitizeMercuryNotebookContent`) strip *runtime metadata* and clear *code-cell\nsaved outputs*. They do **not** neutralize HTML/JS, and they do not touch widget\nvalues or markdown source. \"Sanitize\" here is notebook hygiene, not XSS defense.\n\n## Threat model (attacker → victim, not self-inflicted)\n\nThe CVE-relevant framing is **data-driven**: the app author writes ordinary code,\nand the *data* is attacker-controlled.\n\n```python\nimport mercury as mr\n# `row` comes from a DB / user submission / uploaded file / external API —\n# i.e. NOT authored by the app developer:\nmr.Markdown(row[\"comment\"])\n```\n\nThe attacker supplies the untrusted value (posts the comment, uploads the file,\npoisons the API/RAG source). A **different** user — another app user, a reviewer,\nan admin — then opens the app, and the payload executes in *their* browser. The\nvulnerable component (Mercury's server-side widget rendering) and the impacted\ncomponent (the victim's browser session in the app origin) differ, which is the\nclassic stored-XSS attacker/victim separation.\n\n**Amplifier — session sharing (`--keep-session`).** Mercury can serve one shared\nkernel session to all viewers (`mercury run … --keep-session`, README \"Arguments\":\n\"share the same session between multiple users … others will see this\"). It is\n**opt-in and defaults to off** (`keepSession=False` in `mercury_app/handlers.py`),\nso it is *not required* for the base case — any app that renders one user's\nuntrusted data to another user is already vulnerable. When enabled, content one\nviewer submits is rendered into the session other viewers see, extending this to\ncross-user delivery. Authentication is **opt-in and off by default**: a free\npassword gate exists (`mercury run … --pass=…`, README), while user-based\nauthentication is a paid add-on. Because auth is off unless the operator enables\nit, unauthenticated public deployments — where the attacker needs no account — are\na realistic default.\n\n## Proof of Concept\n\n```python\nimport mercury as mr\n\n# Value that would realistically arrive from untrusted data (DB row, form field,\n# uploaded file, API/LLM response):\nuntrusted = '<img src=x onerror=alert(String.fromCharCode(88,83,83))>'\n\nmr.Markdown(untrusted)   # rendered to raw HTML, unsanitized, into the app DOM\n```\n\nThe generated widget HTML contains the payload verbatim; when the widget is\ndisplayed, the `onerror` handler runs.\n\n### What was confirmed (and how)\n\n- **Confirmed by execution in a real browser (sink level):** driving the *actual\n  `python-markdown` output* into the same `ipywidgets.HTML` `value` sink the widget\n  uses causes the payload to execute in headless Chromium. Execution was captured\n  via Playwright's `dialog` event (which fires only on a genuine `alert()`, so the\n  mere presence of the string in the HTML cannot cause a false positive). A benign\n  control (`**hello**`) produced **zero** dialogs, confirming the harness reports\n  only real execution. `python-markdown` passes `<img src=x onerror=…>` through\n  verbatim by default (behavior is not version-specific).\n- **Reasoned from source (not executed end-to-end):** the full path from a\n  `mr.Markdown(...)` call in a *served Mercury app* to a viewer's DOM was not run\n  end-to-end, because no isolated container/VM was available in the reporting\n  environment. Because `MarkdownWidget` *is* the `ipywidgets.HTML` sink above and\n  Mercury's frontend applies no sanitizer to widget HTML values (the only frontend\n  sanitizer strips notebook metadata at save time), the served-app path is expected\n  to behave identically. Reproduce end-to-end before publishing if you want the\n  advisory to state full-path browser confirmation.\n\n## Impact\n\nMercury shares notebooks as web apps/dashboards, often for non-technical audiences.\nWhen an app renders untrusted data through `mr.Markdown`, the generated page carries\nattacker-controlled script that runs in the browser of any other viewer, in the\napp origin — enabling session/cookie/token theft, UI spoofing and forced actions as\nthe victim, and pivoting within the hosting origin. With `--keep-session`, this\nextends to cross-user delivery within a shared session.\n\n## Severity rationale (CVSS 3.1 per-metric)\n\nBase score reflects the realistic default: an unauthenticated deployment whose app\nrenders untrusted data via `mr.Markdown`.\n\n| Metric | Value | Reason |\n|---|---|---|\n| **AV** Attack Vector | **Network (N)** | App is served over HTTP to remote users. |\n| **AC** Attack Complexity | **Low (L)** | No special conditions or race; supply data that reaches an `mr.Markdown` call. |\n| **PR** Privileges Required | **None (N)** | Baseline: the injection channel (public form/upload/API) needs no account; auth is optional/paid. See variant below. |\n| **UI** User Interaction | **Required (R)** | A victim must open/view the app page for the stored payload to run. |\n| **S** Scope | **Changed (C)** | The vulnerable component (server-side widget render) injects script that executes in a different security authority — the victim's browser session/origin. (This is the canonical XSS scoping in the CVSS 3.1 spec.) |\n| **C** Confidentiality | **Low (L)** | Script can read data/session material available to the app origin; scored L (not H) for a generic app without asserting full account takeover. |\n| **I** Integrity | **Low (L)** | Script can alter the page and act as the victim within the app; scored L generically. |\n| **A** Availability | **None (N)** | No direct availability impact. |\n\nResult: **`CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N` = 6.1 (Medium)**.\n\nDeployment-dependent variants (state your environment's when filing):\n- Injection channel requires an authenticated low-privilege user → **PR:L** →\n  `…/PR:L/UI:R/S:C/C:L/I:L/A:N` = **5.4**.\n- App origin exposes high-value auth material such that XSS yields full\n  session/account takeover → **C:H/I:H** raises the score; justify per deployment\n  rather than claiming it universally.\n\n## Remediation\n\nPrimary — **sanitize by default in `mr.Markdown`, with an explicit opt-out for the\ndeliberate raw-HTML use case** (backward-compatible, non-breaking):\n\n```python\n# mercury/md.py\ndef _to_html(self, text: str, unsafe_allow_html: bool = False) -> str:\n    if md_lib is not None:\n        body = md_lib.markdown(text)\n    else:\n        body = f\"<pre>{escape(text)}</pre>\"\n    if not unsafe_allow_html:\n        # allowlist tags/attributes; strip javascript:/data: schemes and event handlers\n        body = nh3.clean(body)            # or bleach.clean(..., strip=True)\n    return self._apply_inline_theme(body)\n```\n\nExpose `unsafe_allow_html=False` on `mr.Markdown(...)` so authors who deliberately\nembed trusted raw HTML can opt in, while the default is safe. This mirrors the\nconvention used by comparable tools (e.g. Streamlit's `unsafe_allow_html`).\n\nDefense-in-depth: since widget HTML values are written via `innerHTML` without\nsanitization, consider sanitizing widget HTML values at the frontend before they\nreach the DOM, and/or serving a Content-Security-Policy that forbids inline event\nhandlers, so a single missed sink is not immediately exploitable.\n\n## Additional hardening (secondary — not the reported vulnerability)\n\nSeveral widget ESMs write the **label** with `innerHTML`, e.g. `mercury/text.py`\n`topLabel.innerHTML = model.get(\"label\") || …` (same shape in `number.py`,\n`time.py`, `date`/`datetime`/`daterange`/`select`/`json`/`file`, and\n`indicator.py`'s `_card_html`). **This is not an attacker→victim XSS path**: labels\nare static strings set by the app author in Python; URL/`url_params` overrides\naffect only widget `value` (assigned via the safe `input.value` property), never\n`label`, so there is no end-user/URL route into a label. It is a defense-in-depth /\nauthor footgun only. Recommended regardless: render UI strings with `textContent`,\nor `html.escape` labels, so output encoding is applied uniformly.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "mercury"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "3.0.0"
      }, {
        "fixed" : "3.2.11"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/mljar/mercury/security/advisories/GHSA-2658-85cv-9wwq"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/mljar/mercury/commit/c798a85924e6614c6fea7afe5a560e4554a1d09b"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/mljar/mercury"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/mljar/mercury/releases/tag/v3.2.11"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-116", "CWE-79" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-10-19T17:01:20Z",
    "nvd_published_at" : null
  }
}