This PR adds an `api_only` global permission that restricts a Webmin account to one supported API endpoint, such as virtual-server/remote.cgi.
External integrations need credentials that can call an API without also granting access to the Webmin interface or generic RPC. Existing module permissions do not provide this endpoint-level restriction. The new setting allows administrators to create dedicated integration accounts while Webmin continues performing authorized operations through its privileged backend.
The restriction is enforced in two places:
- MiniServ checks the authenticated account's policy before dispatching CGI, static-file, DAV, or WebSocket requests. Requests outside the configured endpoint receive HTTP 403.
- `init_config` requires the permitted CGI to explicitly opt in before initialization. This also protects Webmin-initializing CGIs hosted by another web server.
Generic RPC is denied for API-only accounts, even when an existing RPC permission would otherwise allow it. The endpoint's own module and operation permissions still apply. Selecting an endpoint does not grant permission to execute every API command.
Webmin Users gains an API-only setting for users and groups. Existing restrictions survive ordinary edits, resets, copies, cloning, renaming, group propagation, and cluster synchronization. Clearing a restriction requires an explicit permission edit. Group updates preserve restrictions already assigned to individual members.
MiniServ reads the policy on each request from the account's existing storage backend: local files, MySQL, PostgreSQL, or LDAP. Policy-read errors deny access instead of treating the account as unrestricted.
Validation passed with the four separately submitted supporting fixes (#2897, #2898, #2899, #2900) ,applied: 169 focused tests, syntax checks, and live Debian tests using file-backed and PostgreSQL accounts. Live checks covered account creation, lifecycle operations, both CGI modes, sessions, RPC, static files, DAV, and WebSockets.
The supporting fixes remain separate PRs. This API-only branch currently has seven lifecycle test failures that depend on the file-cache and group ACL cleanup fixes landing.
This patch fixes CSV imports on systems such as AlmaLinux where MariaDB's `PrivateTmp` setting hides Webmin's temporary files.
The earlier permissions fix could not solve this because the database service still could not see the file.
Imports now use a unique directory under `secure_file_priv`, or the database's data directory, while retaining restricted file permissions and automatic cleanup.
The directory uses the `#sql-` prefix so MariaDB does not treat it as a database during listings, backups, or checks.
Verified live on Debian 13, AlmaLinux 10, Ubuntu 26.04 MariaDB and MySQL 8.4, including database listings and full dumps taken while an import is in progress.
This patch fixes mail sending and SMTP monitoring silently continuing without encryption when STARTTLS is rejected.
That fallback could expose passwords and email contents despite encryption being selected.
Both paths now require a valid STARTTLS success response and stop on failure, while successful TLS and explicitly configured plaintext connections remain supported.
This patch fixes MySQL imports that fail because the database server cannot read the temporary file.
Since the temporary copy is created with mode 0600, a server-side `mysqlimport` fails for imports from a local file, and for uploads by users with a Unix user restriction.
Before running the import as root against a local server, the file is now given the group of the running server process with mode 0640, so the server can read it while other users still cannot. The process is found through the server's reported PID file and must be `mysqld` or `mariadbd`; otherwise the permissions are left unchanged.
This patch fixes leaving old bytes in the input buffer when a later read is shorter.
Those extra bytes can corrupt ordinary HTTP RPC requests. Fast RPC is unaffected (discovered in deep tests with Virtualmin WP Workbench).
The reader now matches Perl's native read behavior, with regression tests for buffered and socket reads, offsets, and zero-length reads.
This patch fixes UI library buttons, badges, dropdowns, alerts, and other stateful elements to follow the active theme consistently.
It maps action states and sizes to native theme button classes while retaining safe CSS fallbacks.
This patch fixes package installation when a request contains both installed and missing packages.
DNF 4 uses one `install` transaction, while DNF 5 updates installed packages first and installs missing packages only after the update succeeds.
It preserves architecture package handling, always installs required repository packages, and prevents an empty package list from becoming a full system update.
The complete transaction reads from `/dev/null`, and tests cover DNF 4, DNF 5, installed, missing, mixed, and empty package sets.
Live AlmaLinux testing also confirmed both the single-command and chained-command paths.
This PR fixes package installation pages stopping after "Re-fetching available packages .." on RPM systems, before the System Status refresh, reboot check, and return link appeared.
The regression was introduced by https://github.com/webmin/webmin/commit/658f930, which wrapped RPM queries in `clean_environment` while the Package Updates installer had already cleaned the environment.
The inner clean overwrote the only saved environment, leaving `WEBMIN_CONFIG` unset and causing the System Status library to fail after the page headers had been sent.
Nested `clean_environment` calls now save separate snapshots, allowing each `reset_environment` call to restore the matching environment exactly while preserving Virtualmin's API script runner behavior.
This PR fixes SSL certificate verification for regular `/rpc.cgi` connections.
It reuses the existing certificate requirements already passed to Fast RPC, so both transports honor `checkssl`.
<!-- ANT-2026-1G97HEC6: Reported by Adam via email on October 11, 2026 at 12:08. -->
This PR fixes privilege boundary bypasses in MySQL database backups.
It restricts custom dump parameters and shared backup settings to users with unrestricted root backup access.
It also prevents database names, table names, and compatibility values from being interpreted as dump options.
The changes include focused tests and passed live regression testing with MySQL and MariaDB.
This PR fixes unsafe RPC deserialization by dropping `Data::Dumper` from fast RPC, rejecting `$VAR1` input, and keeping remote objects as plain data.
Original report by Adam emailed October 11, 2026 at 05:34.
This patch addresses non-root MySQL backup hooks remaining unreachable after original patch https://github.com/webmin/webmin/commit/6873c65.
Now it makes before and after commands available when backups run as a configured non-root Unix user.
Root hook execution remains limited to cron-eligible Webmin users, and Usermin remains excluded from backup hooks.
This patch fixes a horrible regression introduced by the original sandbox patch 166cfefa28.
MariaDB sandbox mode blocks the `source` command used by Webmin and Virtualmin restores, breaking all restores.
SQL files are now passed directly to the client while preserving binary-log suppression and compatibility with older clients.
This patch fixes valid symlink paths being mistaken for loops by [c51f0ed4](https://github.com/webmin/webmin/commit/c51f0ed4).
It simplifies only the checked path prefix, preserving the unresolved remainder.
Original loop cases still stop quickly, while long valid chains remain supported.
I reproduced incorrect PHP selection in Virtualmin and WP Workbench, and GoAccess choosing its root log-creation branch instead of the domain-user helper.
This patch fixes `get_module_info()` accepting module names with a trailing newline after the regex anchors were changed.
It preserves the strict validation introduced in my `2f4f017ac` to prevent loading files outside installed modules.
The check directly rejects undefined or empty names and any character outside ASCII letters, digits, underscores, and hyphens, including newlines anywhere in the name.
Regression tests pass and verify that invalid names are rejected before module lookup while valid names remain accepted.
ⓘ Skip invalid `#mysql50#.` entries in SQL and mysqlshow database listings so stray directories don't break the MariaDB page. Preserve valid dot-prefixed, hash-prefixed, and legacy database names.
Reproduce by creating an ordinary `.config` directory in MariaDB's data directory and opening the Webmin MariaDB module. On AlmaLinux, starting `user@27.service` also reproduces the issue because the globally enabled Podman user restart service creates `.config` and `.local` in the mysql account's home. Podman is one possible source, and the failure doesn't depend on it.
Fixes https://forum.virtualmin.com/t/error-accessing-mariadb-server-through-webmin/138118
This PR fixes Webmin being killed when package updates trigger overlapping restarts.
I found this while upgrading packages on a Debian 13 Pro, with the upgrade finished, but Webmin stopped responding, and tracing showed a second `SIGHUP` killing it during startup.
The fix keeps restart and reload signals pending across `exec()` and installs their handlers early in startup.
This PR adds `real_os_version_full` so the dashboard can show Debian point releases such as 12.15.
It preserves existing version comparisons and updates the field through installation, OS refreshes, and manual settings.
Older detection caches are refreshed automatically.
Fixes: https://forum.virtualmin.com/t/os-detection-version-with-point-release-on-dashboard/138091
This PR fixes WebSocket transfers that stall when unread data remains buffered.
Miniserv now drains buffered browser data before waiting for more network traffic.
The receive library avoids extra blocking reads and handles temporary read errors without disconnecting.
Tested and verified over HTTPS with Terminal and live stats on Rocky 10 and Ubuntu 26.04.
I discovered these issues while working on and testing new Cloudmin's SSH-based guest File Manager integration, which I decided to drop for now.
This PR fixes WebSocket routes being lost when miniserv configuration changes multiple times within one second.
Read `miniserv.conf` directly so locked updates use the current configuration.
The previous cache could reuse stale data because it compared modification times in whole seconds.
Add a regression test covering route additions and removals with an unchanged modification time.