Skip to content

Releases: BrowserlessAPI/VortexPanel

VortexPanel v3.5.0 — Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 24 Aug 05:40

New: WAF 2.0 — Per-Site Engine Mode & Scoped Rule Exceptions

A substantial new security layer, adding fine-grained control on top of the existing ModSecurity foundation:

  • Per-site WAF mode and scoped rule exceptions — override the WAF's behavior for individual sites, or carve out specific, auditable exceptions to individual rules, without touching vhost configuration directly. Protocol-integrity rules (request smuggling/splitting) are permanently protected and cannot be excepted, even with a force override — this class of rule stays non-negotiable.
  • Custom rules builder — write and manage custom detection rules through the panel, compiled and validated before being applied.
  • GeoIP blocking — block or allow traffic by country.
  • Rate limiting — per-path request throttling with configurable windows.
  • Caddy / Coraza sync — the same block/allow lists and custom rules now apply consistently to Caddy sites, not just nginx/Apache. Editing lists through the existing interface automatically propagates to Caddy sites too.
  • Recent-hits dashboard and rule catalog — visibility into what the WAF is actually blocking, and a browsable reference of available rules.

This was merged carefully on top of the existing codebase — extracted precisely as the 60 functions genuinely unique to this feature (rather than a raw copy), avoiding a collision with an existing, unrelated Load Balancer status endpoint that a naive merge would have broken.

Security Hardening

  • Domain names are validated before reaching shell commands or filesystem paths, across site creation, WordPress installs, and imported sites.
  • The panel self-updater now rejects anything that isn't a genuine version tag before running git checkout.
  • The terminal WebSocket now enforces the IP allowlist, not just the REST API.
  • Disallowed IPs get a clean 403 instead of a 500. SESSION_COOKIE_SECURE is set for HTTPS deployments. /api/settings/webroot now requires authentication.

Full Multi-Distro App Store Coverage (Ubuntu, Debian, AlmaLinux, Rocky, RHEL, Oracle, CentOS Stream, CloudLinux, Fedora)

  • RHEL/dnf-yum install paths added or corrected for: Apache (httpd), PHP (via Remi), Python, Node.js (via rpm.nodesource), Redis, Supervisor, DDNS (EPEL), MariaDB, phpMyAdmin. Fedora nginx now installs via the base repo correctly.
  • Family-agnostic uninstalls for every app, working across apt, dnf, and yum.
  • A service-name resolver so start/stop/status controls use the actual systemd unit for each distro (httpd, supervisord, mysqld, etc.) instead of assuming Debian's naming.

Correctness Fixes

  • PostgreSQL database-listing crash; MongoDB create/drop; maintenance-mode vhost corruption with proper rollback; RHEL sudo group detection; CDN config-save crash; SSL www. handling restricted to apex domains only; Cloudflare's proxied flag now preserved with retry; DNS serial numbering made monotonic; Docker proxy cleanup on removal; HTTP/3 duplicate reuseport; correct default service user for Go/Node projects; PHP extension and php.ini paths corrected for RHEL; RHEL log-viewer paths; per-distro deploy web-user and unzip handling; AI feature disabled-guard.

WordPress / WP Toolkit
Includes the OpenLiteSpeed fixes from this session's work: correct lsphp binary detection, proper vhRoot/restrained vhost settings, lswsctrl reload instead of a generic restart, log-directory creation, and a corrected install path.

VortexPanel v3.4.18 - Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 23 Aug 03:13
d717513

VortexPanel v3.4.18

Security hardening, correctness fixes, and full multi-distro App Store coverage across all 9 supported distributions.

🔒 Security
Domain validation before any value reaches a shell command or filesystem path — site/WordPress create, clone, and imported-site paths (closes command-injection and path-traversal vectors, including untrusted domains parsed from imported backups).
Self-updater injection fixed — the version field is now constrained to a real version tag before it reaches git checkout.
Terminal WebSocket (/ws/…) is now covered by the IP allowlist, not just /api/ — a stolen cookie can no longer open the root shell from an unlisted IP.
Disallowed IPs return a clean 403 instead of a 500; SESSION_COOKIE_SECURE is set for HTTPS deployments; /api/settings/webroot now requires auth.
Removed the hardcoded admin/admin123 credential fallback (random password generated instead).

🐧 App Store — all 9 distros (Ubuntu, Debian, AlmaLinux, Rocky, RHEL, Oracle, CentOS Stream, CloudLinux, Fedora)
Added RHEL-family (dnf/yum) install paths: Apache (httpd), PHP (Remi), Python, Node.js (rpm.nodesource), Redis, Supervisor, DDNS (EPEL), MariaDB (package-manager-agnostic), phpMyAdmin (portable). Fedora nginx now uses the base repo.
Family-agnostic uninstalls for every app (apt + dnf + yum).
New service-name resolver so start/stop/status use the correct unit per distro (httpd, supervisord, mysqld).

🛠️ Correctness & logic
Fixed: PostgreSQL DB-listing crash, MongoDB create/drop, maintenance-mode vhost corruption (with rollback on failed nginx -t), RHEL sudo-group assignment, CDN config-save crash.
SSL now requests www. only for apex domains (subdomain certs no longer fail); Cloudflare proxied flag preserved with retry-on-failure; monotonic DNS zone serial; Docker proxy cleanup on container removal; HTTP/3 duplicate reuseport prevented.
Go/Node.js project services default to a real web user; PHP extension management and php.ini paths work on RHEL; RHEL log-viewer paths; per-distro deploy web-user and unzip; AI quick-actions honor the disabled flag.

📦 WP Toolkit
Includes the OpenLiteSpeed fixes (correct lsphp detection, vhRoot/restrained, lswsctrl reload, log-dir creation) and the install-path fix.

VortexPanel v3.4.14 – v3.4.16 — Combined Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 17 Aug 17:07

VortexPanel v3.4.14 – v3.4.16 — Combined Release Summary

Security
OS command injection fixed across file management (v3.4.14) — search, scan, compress, extract, and lint in the file manager were vulnerable to shell command injection via unsanitized input passed to shell=True subprocess calls. Confirmed exploitable with a real proof-of-concept before fixing; every affected call converted to safe argument-list form.

The real root cause behind repeated install failures (v3.4.14)

Discovered that panel/routes/os_utils.py silently overrides the main App Store install logic for eight core apps — nginx, MariaDB, PostgreSQL, Redis, MongoDB, Docker, Node.js, and PHP — on the actual "Install" button. Earlier fixes made directly to the visible install scripts for these apps had no effect, because this hidden layer ran instead. Once found, the real Debian/Ubuntu path bugs for nginx, MariaDB, MongoDB, PHP, and Node.js were fixed in the code that actually executes.

CloudLinux and general RHEL-derivative detection (v3.4.15)

CloudLinux was completely unrecognized by OS detection — since it wasn't in any matched list, it silently fell through to the code's own default value of "Debian," meaning every affected app would have tried apt-get commands on a dnf/yum system. Fixed with explicit CloudLinux recognition, plus a general fallback so any future or currently-unlisted RHEL/Fedora derivative is caught the same way.

Full CentOS Stream 9 / RHEL-family audit — all 26 App Store modules (v3.4.16)

The most significant fix: nginx and MongoDB's RHEL repo files were built via an unquoted bash heredoc, causing 𝑟 𝑒 𝑙 𝑒 𝑎 𝑠 𝑒 𝑣 𝑒 𝑟 ‘ / ‘ releasever‘/‘basearch — variables meant for DNF to resolve — to be silently expanded to empty strings by bash before DNF ever saw the file. This produced a permanently broken URL (.../rhel///) on every single RHEL-family install. Reproduced this directly before fixing.

Also fixed, individually verified per app:

Apache2 — install-check never recognized httpd (the actual RHEL binary name), so a successful install still reported as failed
OpenLiteSpeed — had no RHEL-specific install path at all, and hit a real, independently-confirmed upstream OpenLiteSpeed packaging bug on EL9; added the community-confirmed Remi repository workaround
Pure-FTPD — tried installing a package (pure-ftpd-common) that doesn't exist on RHEL, failing the entire install
ClamAV — used entirely wrong RHEL package and service names
Roundcube — wrong PHP package name, plus a hardcoded system user that doesn't exist on RHEL
ModSecurity — RHEL's nginx connector now compiles from source against the actually-installed nginx version, avoiding a likely binary-compatibility mismatch from a prebuilt package

Individually verified as already safe: MySQL, MariaDB, PostgreSQL, Redis, Docker, Bind9, Memcached, Composer, Supervisor, ffmpeg, DDNS Manager, CDN Manager, Caddy, Nginx Load Balancer. Node.js's RHEL install path confirmed still current against NodeSource's own official documentation.

Also in this range
Fixed the Quick Install command in the README using wget, which isn't present on minimal installs like CentOS Stream 9 — switched to curl, which is far more universally available.

VortexPanel v3.4.12 — Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 13 Aug 04:11

WP Toolkit installs would hang indefinitely with no feedback. The entire install — WordPress download, database creation, wp-cli setup, vhost creation, cron configuration — ran as a single blocking request, genuinely capable of exceeding gunicorn's 120-second worker timeout under real network or disk conditions. A killed worker gives the browser nothing at all, which is exactly what "stuck, nothing happens" looks like. Converted to a background job with real status polling, matching the same pattern already proven for App Store installs and Panel Update.

Creating a new site with "Create Database" and "Create FTP Account" checked did neither. Confirmed directly: the frontend was sending both flags correctly, but the backend never read them — not new to this update, a pre-existing gap. Wired both to the existing, working database and FTP creation logic, with the site itself never failing just because these optional extras do.

A live crash in database user creation. While fixing the above, found that _sql_escape() was called nine times across create_db, create_user, change_password, drop_user, and grant_db — but was never actually defined anywhere in the file. Any ordinary "create a database with a user and password" request was throwing an unhandled 500. Verified this crashed live before fixing it, then verified the database, database user, and FTP account all genuinely exist afterward.

Security update apply looked like it was doing nothing, over and over. For kernel and firmware packages specifically, apt genuinely installs the new version, but the running kernel/module stays active until reboot — and the panel had no way to distinguish "this actually needs a reboot" from "this failed." Added real detection of Ubuntu's own /var/run/reboot-required signal, with a clear explanation in both the result panel and the toast notification instead of an endless-looking loop.

phpMyAdmin's PHP version and port settings only worked on nginx. The install script itself correctly detects and configures nginx, Apache, or Caddy — but the Save actions for both settings were hardcoded to check only nginx's config path, failing with "Config not found" for anyone running Apache or Caddy. Tested against real config files for all three web servers before and after the fix. Also hardened the install-completion check, which previously only verified a directory existed — created in the very first install step, before any real work happened — rather than checking for the actual config file that only exists once installation genuinely completes.

VortexPanel v3.4.11 — Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 06 Aug 10:14

PHP Webshell Scanner missed hardcoded reverse shells entirely. Every detection pattern for exec()/shell_exec()/passthru()/popen()/proc_open() required a $_GET/$_POST/etc. variable to be present — a webshell with the command simply baked in as a string bypassed every single one. Confirmed via a security researcher's report: reproduced their exact payload, got a clean scan result, then fixed it. Rather than flag every hardcoded call to these functions unconditionally (which would misfire on legitimate exec() use — ImageMagick, ffmpeg, git deploy hooks), the fix is tiered by confidence: CRITICAL when a hardcoded call also contains a known reverse-shell indicator (/dev/tcp/, bash -i, mkfifo, etc.), MEDIUM for any other hardcoded call, flagged for manual review rather than silently missed. Caught and fixed a real bug in the first version of this fix during testing — the regex excluded quote characters from its match window, which broke on the report's own payload (a double-quote nested inside a single-quoted shell command, a completely normal pattern).

MySQL's version list was wrong on every option, and the "9.x" one didn't actually work. Verified against current reality: Oracle moved the Innovation track to calendar versioning in June 2026 (current release is genuinely 26.7.0, not a bug), MySQL 8.0 reached End-of-Life in April 2026 and was never actually an "LTS" release despite being labeled one, and the 9.7 LTS line was missing from the list entirely. Separately, the install script was trying to install a package named mysql-server-9.x, which never existed — that failure was silently papered over by a fallback to a generic install. Version list corrected, and Innovation now installs deterministically instead of failing first.

MariaDB uninstall left a mysql-common residue that broke later MySQL installs. Confirmed directly from a user's own server output: an rc-status (removed, not installed) leftover package with "maria" in its version string was being matched by the MySQL conflict guard as if MariaDB were still present. Fixed the guard to require genuine installed status, and fixed the uninstall script to explicitly purge this package so the residue can't recur.

Security Updates check was hitting the network on every single page visit. Previously re-ran a real apt-get update + apt-get -s dist-upgrade on every Dashboard or Settings navigation. Now cached for 4 hours, shared correctly across all worker processes.

VortexPanel v3.4.10 — Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 05 Aug 08:10
362a1d3

VortexPanel v3.4.10 — Release Summary

Security Updates check was re-running on every single page visit. Previously "non-blocking" only meant it didn't freeze the UI — it still triggered a real apt-get update + apt-get -s dist-upgrade (or dnf equivalent) on every Dashboard or Settings navigation, hitting the network and the package manager repeatedly for no real benefit. Now cached for 4 hours (file-based, correctly shared across all gunicorn worker processes). Measured directly: first check ~11 seconds, every subsequent visit within the window: instant.

ClamAV wouldn't install. The install script downloaded ClamAV's own vendor .deb directly from clamav.net and installed it via dpkg -i. That succeeded — but the vendor's package is a generic, portable build that doesn't include Ubuntu's systemd unit files at all, so enabling clamav-daemon/clamav-freshclam failed with "Unit file does not exist" even though the software itself installed. Switched to installing via the distro's own package instead (confirmed genuinely current — same version the vendor offered), which correctly ships every unit.

Applying that same audit to other App Store modules turned up the identical risk in Fail2ban's install script (same vendor-.deb-via-dpkg -i pattern). Made it defensive: it now explicitly verifies the systemd unit exists after install and falls back to the distro package if not, rather than trusting dpkg's exit code alone.

Fedora misdetection in the Security Updates check. Same root cause as an earlier fix elsewhere this cycle — OS-family detection read $ID_LIKE alone, which Fedora doesn't set at all (it's the upstream of the RHEL family, not a derivative), so the check silently matched neither branch on Fedora.

Improved
PHP webshell scanner. Tested real evasion techniques against the existing patterns rather than assuming coverage, and found:

File extensions .phtml, .phar, .php3/4/5/7, .pht were never scanned at all, regardless of content — some of these genuinely execute as PHP on real server configs
Five execution techniques had zero pattern coverage: PHP's backtick shell-exec operator, proc_open(), pcntl_exec(), and user input passed as a callback to register_shutdown_function/array_map/usort/etc.
Added an honest heuristic (explicitly labeled as such) for decode-and-write split across two lines, which no single regex can catch

All fixes regression-tested together against real evasion payloads plus a deliberately benign file — every evasion caught, zero false positives.

Added
CyberPanel support in the website import wizard, alongside cPanel, aaPanel, and HestiaCP. Built against CyberPanel's actual open-source backup code rather than inferred from documentation — correctly handles both their current backup format (meta.xml + plain public_html/ folder) and their older pre-2.0 format (public_html.tar.gz), detects addon/parked domains from the backup metadata, and honestly flags database dumps as best-effort matches for manual verification, since CyberPanel doesn't use one fixed path across versions.

VortexPanel v3.4.9 — Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 01 Aug 15:30

Mail actually delivers now
Account, domain, and forwarding management always wrote correctly to Postfix's lookup tables — but nothing ever told Postfix to use them. virtual_mailbox_base, virtual_uid_maps, and virtual_gid_maps shipped empty, so no mail was ever actually delivered to a mailbox regardless of what the panel showed. New /api/mail/setup configures the full chain — vmail system user, Postfix's virtual maps, and delivery via Dovecot LMTP rather than Postfix writing maildirs directly (which is the classic cause of "delivered but invisible in IMAP"). Also fixed a related bug: the panel stored password hashes in its own file, which Dovecot never read, so even a correctly-created account couldn't authenticate — deleting an account or resetting its password had no real effect either. Verified with an actual message sent, delivered, and read back via IMAP.

Kernel live patching.
VortexPanel can't implement this itself — it requires each provider's own binary-diffing toolchain per kernel build. Instead, this detects, installs, and reports real status for the two providers that actually exist: Canonical Livepatch (free, Ubuntu-only, ~5-10% CVE coverage) and TuxCare KernelCare (paid, covers all 9 supported distros, far broader coverage). Surfaces reboot_required and pending kernel packages, since that's exactly the blind spot live patching exists to close.

Fixed
Fedora was silently broken across 12 install scripts. Reviewing a community DNS module surfaced a real bug in my own earlier RHEL-family work: detection read $ID_LIKE alone, but Fedora — being the upstream of the RHEL family rather than a derivative — ships no ID_LIKE field at all. On real Fedora, this produced an empty string matching neither the Debian branch nor the RHEL branch, so nginx, Caddy, PHP, BIND9, Fail2ban, and Apache2 installs would silently do nothing there. Fixed to check $ID and $ID_LIKE together, verified against real Fedora 43 /etc/os-release output.

VortexPanel v3.4.8 — Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 26 Jul 15:53

Genuine ModSecurity WAF support for Apache — this was previously decorative. The "Apache legacy" version option existed in the App Store dropdown, but selecting it ran the identical nginx-only install script regardless, which always failed since Apache doesn't have nginx installed. Built real, tested Apache support across the entire feature, not just the installer:

  • Install: libapache2-mod-security2 + OWASP CRS v4.x (matching nginx's CRS version for consistency, rather than the older v3.3.5 Ubuntu bundles separately)
  • Uninstall: now actually detects and removes the correct package set — previously it only ever targeted nginx packages, silently leaving a real Apache install completely untouched
  • Full status/control API — Engine Mode toggle, Paranoia level, Custom Rules, IP/UA/User-Agent/URL lists, audit log, and the CRS repair/update tools all now correctly detect and operate against whichever webserver is actually active
  • Fixed a related false-negative: the post-install verification check was still nginx-only, so a successful Apache install was incorrectly reported as failed
  • Fixed the Security Score widget showing ModSecurity as inactive on a genuinely working install
  • Fixed the WAF Analytics page requiring a manual refresh after installing — it now updates live the moment an install/uninstall completes

Fixed

  • apt lock contention — a genuinely concurrent apt-get call (e.g. an App Store install running alongside the Security Updates check) would fail every install instantly with "Could not get lock" instead of waiting a few seconds for the other process to finish. Added a real retry wrapper.
  • Stale version labels — nginx (now correctly shows 1.30.4/1.31.3, both patched against the recent CVE-2026-42533 RCE), Caddy (2.11.4), and PHP (corrected EOL/security-only status across all listed branches, and reordered so an EOL version is no longer the pre-selected default).

VortexPanel v3.4.6 — Release Summary

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 25 Jul 15:52

UI
Docker catalog and CDN Manager card grids — cards had no consistent height, so action buttons landed at different vertical positions depending on how much content each card happened to have. Rebuilt as proper flex columns with pinned button rows.
App Store's PHP row layout — the Settings/Uninstall/version-picker button group was misaligned; restructured into clean, consistent rows.

Security
Shell-injection audit across FTP, Mail, Security, Databases, and Settings modules — found and fixed genuine, tested vulnerabilities in password handling (FTP account creation/password changes, mail account passwords, sudo user creation, database user passwords across MySQL/PostgreSQL/MongoDB) and a completely unvalidated, unquoted hostname field. Each fix verified with a real injection payload, not just code review.
PostgreSQL query execution hardened to match MySQL's existing safer pattern (queries via temp file instead of embedded shell strings), closing a second injection vector that survived the first round of fixes.

Functional gaps closed
Directory Protection tab — the Anti-XSS (open_basedir) and Access Log toggles were purely decorative with zero backend. Now genuinely functional, using a per-directory .user.ini approach that doesn't touch the shared PHP-FPM pool other sites depend on.
Password/Limit Protection tab — the password field was silently defaulting to "changeme" regardless of what was typed, and the delete endpoint had never worked at all (wrong marker format).

Platform support
Genuine RHEL-family support for BIND9/DNS Manager and Fail2ban. Both were apt-only and would fail to install entirely on RHEL, Fedora, CentOS, AlmaLinux, Rocky, Oracle Linux, or CloudLinux. DNS zone management also needed rebuilding — RHEL-family's config layout differs from Debian's and the earlier fix only handled the Debian path.

Added
Security updates advisory — a dashboard banner and full Settings-page section for pending OS security updates, distinct from the existing "Panel Update" button (which blindly upgrades everything). Detects security-tagged updates using each distro's own native tooling rather than a hardcoded CVE list that would go stale, and includes a real "apply only these" action — tested end-to-end against 121 genuine pending updates on a live system, confirmed all applied correctly.

VortexPanel v3.4.5 — Reliability Hardening

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 22 Jul 06:10

v3.4.5 — Reliability Hardening

This release is the result of a full functional test pass against real
running services (not just code review) across Mail, DNS, Cron, and
Fail2ban — plus verification passes on ModSecurity WAF, UFW Firewall,
and Docker deploy.

Fixed

  • Cron Jobs — disabling a job made it silently vanish from the job
    list instead of showing as disabled, with no way to re-enable it
    through the UI
  • Mail — new mail accounts had their maildir created with the wrong
    directory structure, silently breaking every new mailbox's ability to
    receive mail
  • DNS — zones created through the panel were written to disk
    correctly but never actually declared to BIND9, meaning every zone
    created through VortexPanel was completely unservable
  • Fail2ban — website anti-CC/anti-scan jails were silently
    monitoring the wrong log source entirely due to an unset backend,
    meaning they never actually detected or banned anything

Verified, no issues found

  • ModSecurity WAF — full validation/escaping/rollback chain confirmed
    working against a real ModSecurity engine
  • UFW Firewall — confirmed working down to actual kernel-level iptables
    rules
  • Docker deploy — command generation confirmed correct, including
    special-character handling in environment variables