
Python PoC that forges a hard-coded HS256 JWT to exploit CVE-2026-89026 in Issabel pbxapi, enabling unauthenticated remote OS command execution via the originate endpoint.
Issabel pbxapi hard coded JWT RCE POC
Issabel Framework pbxapi — unauthenticated JWT forge (hard-coded HS256 key) then GET /pbxapi/manager/originate with Application=System to run OS commands as the Asterisk user. Patched in commit b97dbaf (key loaded from /etc/issabel.conf). Shadowserver saw exploitation from 2026-09-09.
For authorized testing only. Do not run this against systems you do not own or have permission to test.
Requires: Python 3, standard library only.
python3 cve-2026-89026-issabel-pbxapi-jwt-rce.py -u https://TARGET --test --insecure
python3 cve-2026-89026-issabel-pbxapi-jwt-rce.py -u https://TARGET --read /etc/passwd --insecure
python3 cve-2026-89026-issabel-pbxapi-jwt-rce.py -u https://TARGET --cmd id --insecure
python3 cve-2026-89026-issabel-pbxapi-jwt-rce.py -u TARGET --test
| Flag | What it does |
|---|---|
-u / --url | Issabel base URL (required). http:// or https://. A hostname with no scheme is tried as HTTPS first, then HTTP. http→https redirects keep POST. Bad TLS certs are retried without verify; --insecure skips verify from the start (Issabel often uses a self-signed cert) |
--test | Fingerprint /pbxapi and prove a forged admin JWT is accepted. No originate / no command |
--read PATH | Run cp PATH into the web root via System, then GET the file (this is how you see /etc/passwd) |
--cmd CMD | GET /pbxapi/manager/originate?application=System&data=CMD. AMI does not return stdout — use --read to view a file |
--channel | Originate Channel (default Local/s@default) |
--insecure | Skip TLS verify |
--timeout | HTTP timeout seconds (default 30) |
--test endpoints: GET /pbxapi/ without Authorization (expect 403), then the same URL with Authorization: Bearer <forged JWT>. A 200 JSON listing controllers / manager (or AMI connect JSON after auth) is VULNERABLE. It does not call originate.
Auth: there is none for the attacker. The API thinks it has Bearer JWT auth. Pre-patch pbxapi/index.php sets JWT_KEY to a string compiled into every install. The PoC HS256-signs {iat, exp, data.name=admin} with that key. Post-patch the key is base64_decode(pbxapijwtsecret) from /etc/issabel.conf and the stock token is rejected (NOT_VULNERABLE).
Stdout: PBXAPI, VULNERABLE, NOT_VULNERABLE, NOT_FOUND, HANDLER, HTTP.

CVE: CVE-2026-89026. Credit: Shadowserver Foundation / VulnCheck. Patch: b97dbaf.