Skip to content

VLN-054 — Webmin on CEDAR and MAPLE is reachable only from the Cloud Run connector

Classification: CONFIDENTIAL — Internal Use Only

Status: OPEN. Raised 2026-09-08. Not remediated.

A root-capable web administration interface is exposed on both cloud hosts to exactly one network origin — 10.8.0.0/28, the Serverless VPC connector — where no administrator sits and five internet-facing Cloud Run services do. It is not reachable from the management network the documentation says governs it.

Unlike VLN-053, this service enforces TLS — and on CEDAR nobody can log into it at all: the sole account is root and root's password is locked (§6.2). The finding is not "Webmin is open". It is that a root-owned listener is needlessly exposed to an origin no operator uses, where the only remaining attack surface is whatever can be reached before authentication.

Severity downgraded High → Medium on 2026-09-08 (§7) when that check was finally run. MAPLE has not been checked and must not be assumed to match.


1. Summary

Finding ID VLN-054
Severity Medium — argued in §7, not computed. Downgraded from High 2026-09-08 when passwd -S showed root locked (§6.2). Becomes Critical if 2.621 carries a pre-auth RCE
Affected CEDAR (172.16.0.13) and MAPLE (172.16.0.12), 10000/tcp — both Medium, both measured (§6.3)
Software Webmin 2.621 (webmin-2.621-1.noarch), miniserv.pl, both hosts
Discovered 2026-09-08, while enumerating the ruleset for VLN-053
Class Needless exposure of a privileged management interface
Remediated? No. Remediation proposed in §8, deliberately not implemented
Revised 2026-09-08 (v1.1) — §6.1 added: the only account is root and it stores no hash
Revised 2026-09-08 (v1.3) — §6.2: root is locked; severity downgraded High → Medium
Revised 2026-09-08 (v1.4) — §7.1 pre-auth question resolved (none published); §7.2 added: the mitigation is a state, not a control
Revised 2026-09-08 (v1.5) — §6.3: MAPLE's root also locked, but MAPLE remains unrated — its account list is unread
Revised 2026-09-08 (v1.6) — §6.3: MAPLE measured (root:x, LK); matches CEDAR, rated Medium. Both hosts now complete
Revised 2026-09-08 (v1.7) — miniserv.log read: the config-write caveat was the author's own probe; no logins recorded. Option C now recommended
Revised 2026-09-08 (v1.8) — §5 corrected: Grafana is not management-reachable either; the cloud rule denies what the host rule permits
Revised 2026-09-08 (v1.9) — §8.2: MAPLE has no Webmin log; recorded as ambiguous, not as "no logins"

Why it is a separate finding. It shares an origin with VLN-053 and nothing else: different service, different authentication posture, different remediation, different host set. Folding it into VLN-053 would bury a root-capable interface inside a finding about a database.


2. What was measured, and what was not

Everything below is a read. Service state, listening sockets, package version, the firewall ruleset, and Webmin's own configuration.

No login was attempted. No credential was supplied, guessed, or tested. The authentication posture in §6 is read from /etc/webmin/miniserv.conf, not inferred from a login attempt — deliberately, because probing authentication on a root-capable interface is the kind of "verification" that becomes an incident.

One caveat against the author — RESOLVED, and it was the author. An unauthenticated GET to https://127.0.0.1:10000/ was issued on CEDAR to establish TLS behaviour (§6), and /etc/webmin/miniserv.conf showed an mtime within a minute of it. That was flagged as unresolved rather than dismissed, because a config write on a security host should not be attributed to nobody.

/var/webmin/miniserv.log settles it. The entire log is three lines:

127.0.0.1 - - [08/Sep/2026:15:10:55 +0000] "GET / HTTP/1.1" 401 23280
127.0.0.1 - - [08/Sep/2026:15:10:55 +0000] "GET / HTTP/1.1" 302 0
127.0.0.1 - - [08/Sep/2026:15:10:56 +0000] "GET / HTTP/1.1" 401 23280

Three requests, all from 127.0.0.1, matching exactly what was run: the HTTPS GET (401, login page), the plain-HTTP test (302, redirect to TLS), and the header fetch (401). The miniserv.conf mtime of 15:10:54 sits one second ahead of the first completed request, which is consistent with a write during connection setup. The activity was the author's, and nothing in that timestamp indicates another party.


3. What is exposed

miniserv.pl — Webmin's own web server — running as root, on both hosts:

Host Listener Service state
CEDAR 0.0.0.0:10000 and [::]:10000 active, enabled (starts at boot)
MAPLE 0.0.0.0:10000 and [::]:10000 active, enabled (starts at boot)

Webmin administers the host: users, packages, services, filesystem, cron, and a command shell. Authenticating to it is equivalent to a root shell. There is no lower-privilege mode in play here.

Both listeners bind all interfaces. Neither binds loopback. Nothing but the host firewall stands between the listener and any origin that can route to it.


4. Reachability — from the artifacts

Captured as root on each host, firewall-cmd --list-all, reproduced verbatim for the relevant rule:

CEDAR

rule family="ipv4" source address="10.8.0.0/28" port port="10000" protocol="tcp" accept

MAPLE

rule family="ipv4" source address="10.8.0.0/28" port port="10000" protocol="tcp" accept

That is the entire permission set on both hosts. One origin. Both zones are drop with target: DROP, so everything else is dropped.

10.8.0.0/28 is the gpus-vpc-connector. 5 of the 10 Cloud Run services in gpus-infra egress through itgpus-forms-backend, gpus-forms-clamav-worker, gpus-security-backend, gpus-soc-backend, gpus-status-backend — and all five are ingress: all.

4.1 Nobody administers Webmin this way, and nobody can

The management network 192.168.124.0/24 is permitted 22/tcp on both hosts, and 3000/tcp (Grafana) on MAPLE. It is not permitted 10000/tcp on either.

So an administrator on the management network cannot reach Webmin at all. Any real human use of it goes through an SSH tunnel to loopback:

ssh -L 10000:127.0.0.1:10000 cedar

That path needs no firewall rule. It works with 10000 closed to every network origin, because it arrives on 127.0.0.1.

This is the finding in one sentence. The 10000 rule grants access to the one origin where no operator exists, denies it to the network where operators do, and is unnecessary for the only workflow that actually uses the service. Whatever it was for, it is now pure attack surface.


5. The documented control does not describe these hosts

defense-in-depth.md states:

All Webmin, Grafana, Kibana, and Prometheus interfaces are accessible from the management network (192.168.124.0/24) only. They are not reachable from the production network or internet.

Measured against the artifacts, on the cloud hosts:

Interface Host Management net? Connector? Statement holds?
Grafana 3000 MAPLE no — see below yes no
Prometheus 9090 MAPLE no yes no
Kibana 5601 CEDAR no yes no
Webmin 10000 CEDAR, MAPLE no yes no

The statement is wrong in both directions: none of the four is reachable from the management network, and all four are reachable from an origin the document never mentions.

Corrected 2026-09-08 — Grafana was listed as management-reachable, and it is not

An earlier revision of this table put Grafana as reachable from 192.168.124.0/24, because MAPLE's firewalld carries rule family="ipv4" source address="192.168.124.0/24" port port="3000" protocol="tcp" accept.

The host rule permits it and the cloud rule does not. maple-ingress does not list 192.168.124.0/24 among its source ranges at all, and the only rule that does — allow-onprem-via-vpn — grants just tcp:22, tcp:443, tcp:8080 and ICMP. No GCP rule permits tcp:3000 from the management network, so it is denied before it reaches the host firewall that would have allowed it.

This is the third layer-disagreement found on these two hosts, and the first pointing the other way: §4.3 of VLN-053 records the cloud rule being broader than the host's, and here the host rule is broader than the cloud's. Both directions produce the same class of error — a reachability claim made from one layer.

The firewalld rule is therefore dead: it grants access that nothing can use. Not harmful, but it is another instance of the GOV-038 pattern — a permission with no consumer, retained because nobody assembled the two-layer picture.

access-control/roles.md compounds it — it lists Webmin endpoints for the four WDC servers on 192.168.124.x and does not list CEDAR or MAPLE at all. Two root-capable interfaces are absent from the access-control register.

This is the part most likely to matter in an audit. A reviewer reading either document concludes the admin interfaces are management-network-only. Neither the exposure nor the two cloud hosts appear anywhere in that picture.


6. Authentication posture — read from config, not tested

From /etc/webmin/miniserv.conf on CEDAR:

ssl=1
no_ssl2=1
no_ssl3=1
ssl_honorcipherorder=1
no_sslcompression=1
ssl_hsts=1
ssl_enforce=2
no_trust_ssl=1
session=1
passdelay=1
blockhost_failures=5
blockhost_time=60
logout=/etc/webmin/logout-flag
logout_script=/etc/webmin/logout.pl
denyfile=\.pl$

What is present, and it is not nothing. TLS is on and enforced (ssl_enforce=2, corroborated by an observed 302 from HTTP to HTTPS), SSLv2 and SSLv3 are disabled, HSTS is set, TLS compression is off, and cipher order is server-controlled. Authentication is session-based (session=1) rather than HTTP Basic, with a failed-login delay (passdelay=1) and host blocking. Session cookies were observed carrying secure; httpOnly.

What is absent, and matters:

  • No twofactor_provider. No second factor on a root-equivalent login.
  • No allow= or deny= directive. Webmin supports an application-level IP allow-list and none is configured. The firewall is the only access control — the same single-layer pattern as VLN-053 §4.6.
  • blockhost_time=60 is 60 seconds, after blockhost_failures=5. That throttles online guessing rather than stopping it: roughly 5 attempts per minute, ~7,200/day per source, indefinitely. It is a speed bump, not a lockout.

6.1 There is exactly one account, and it is root

cut -d: -f1 /etc/webmin/miniserv.users returns a single line: root.

No password hash is stored for it, and that is arithmetic rather than inference. The whole file is 9 bytes. root is 4 characters; two field separators are 2 more; a trailing newline is 1. That leaves at most 3 characters for the password field — and the shortest thing that could be a stored credential, a traditional DES crypt hash, is 13 characters. Modern formats are far longer. Whatever is in that field, it is not a hash.

So Webmin is not holding its own credential. One of two things is true, and they are not close in consequence:

Field 2 Meaning Consequence
x Unix/PAM authentication — Webmin validates against /etc/shadow The Webmin login is the system root password. A correct guess against the §4 origin is a root shell, with no second factor and a 60-second speed bump
* or ! Login disabled Nobody can authenticate at all. The listener is still exposed and still root-owned, but §7 falls well below High

Measured 2026-09-08, printing field lengths only so that no credential material left the host:

# sudo awk -F: '{print $1, length($2), length($3)}' /etc/webmin/miniserv.users
root 1 1

The password field is exactly one character. That closes the arithmetic above: it is a placeholder, and a one-character field cannot be a credential under any hashing scheme. Webmin stores no password for root.

The placeholder is x. Unix/PAM authentication is confirmed:

# sudo cut -d: -f2 /etc/webmin/miniserv.users
x

So the Webmin login on CEDAR is the system root password, validated against /etc/shadow. Reading that one character disclosed nothing — a single character cannot be a credential — and it resolves §6.1 to the worse of the two branches.

Stated plainly: a correct guess of the host's root password, offered to 10.8.0.0/28 on port 10000, is a root shell on CEDAR. There is no second factor, and blockhost_failures=5 with blockhost_time=60 permits roughly 5 attempts per minute, indefinitely, per source.

6.2 …and the login is not usable. root is locked.

The dependency above was checked, and it went against the preceding paragraph:

# sudo passwd -S root
root LK 1969-12-31 0 99999 7 -1 (Password locked.)

LK — the root password is locked in /etc/shadow. pam_unix refuses authentication for a locked account, so the Unix delegation in §6.1 resolves to a login that cannot succeed.

Put together: the only Webmin account is root; root authenticates against /etc/shadow; and /etc/shadow has no usable password for it. Nobody can log into Webmin on CEDAR. The credential-guessing path described in §6.1 — 5 attempts a minute against the host's root password — does not exist. That paragraph is kept above rather than deleted, because the reasoning was sound and only the last input changed it; but it does not describe this host.

This is the check that should have been run before the rating

v1.0–v1.2 of this page rated the finding High, resting substantially on a guessable root login. That rating was published across three revisions before passwd -S was run. The chain x"the Webmin login is the system root password" was correct at every step and still produced a wrong conclusion, because it stopped one layer short of the credential store.

Same failure shape as this register keeps recording, and as VLN-053 §4 recorded against its own author: reading one layer and stopping. The severity is corrected in §7.

6.3 MAPLE — measured, and it matches

MAPLE was deliberately not assumed to match CEDAR. It was measured, and the conjunction closes:

# sudo passwd -S root          [on MAPLE]
root LK 1969-12-31 0 99999 7 -1 (Password locked.)

# sudo cut -d: -f1,2 /etc/webmin/miniserv.users     [on MAPLE]
root:x
CEDAR MAPLE
Sole Webmin account is root confirmed confirmed
That account delegates to Unix auth (x) confirmed confirmed
root is locked in /etc/shadow confirmed confirmed

All three hold on both hosts, so nobody can log into Webmin on either.

Why this was measured rather than inferred. The two hosts share a package, a version, a firewall rule and a locked root — an inviting basis for concluding parity without checking. But a locked root only produces an unusable login if root is the sole account and it delegates to Unix auth. Had MAPLE's miniserv.users held a second account, or root with a real stored hash instead of the x placeholder, that account would authenticate inside Webmin, never consult /etc/shadow, and the lock would have been irrelevant to it. Parity on one input is not parity on the conjunction. It happened to match; that was not knowable in advance, and this workstream has already corrected three read-one-layer-and-stop errors.

MAPLE's stakes remain higher if the state ever changes. MAPLE is the Wazuh manager. A root compromise there does not merely expose alerts — it compromises the pipeline meant to notice a compromise, including its ability to report on itself. Both hosts rate Medium today; if §7.2 ever comes true and a root password is set, MAPLE's consequence is the more severe of the two.


7. Severity — argued, and DOWNGRADED 2026-09-08

Medium. Revised down from High, which this page carried through revisions v1.0–v1.2.

The downgrade, stated plainly

High rested on a guessable root login: one account, root, delegating to Unix auth. Every step of that was correct. It was still wrong, because /etc/shadow has the root password locked (§6.2), so the login cannot succeed at all. The rating is corrected rather than defended, and the original reasoning is left visible above so the correction can be audited instead of taken on trust.

Why not High any more: there is no authentication path. The sole account cannot authenticate, so credential guessing, credential stuffing and password reuse are all off the table. TLS is enforced, and network reach is one origin.

Why not Low: what remains is not nothing. miniserv.pl runs as root, binds 0.0.0.0 and [::], is enabled at boot, and is reachable from the egress path of five ingress: all Cloud Run services. A locked account closes the authenticated attack surface and closes none of the pre-authentication surface — every byte a remote caller sends still reaches a root-owned Perl web server before any login is evaluated. And the exposure buys nothing (§4.1): no operator reaches Webmin this way, and no workflow depends on it.

The trigger to Critical was assessed and did not fire (§7.1). No pre-authentication vulnerability is published against 2.621; every advisory in later releases needs an authenticated session. That was the one branch that could have overridden §6.2, and it did not.

What holds the rating up rather than letting it fall to Low is §7.2: the locked account is a state of /etc/shadow, not a control in Webmin. Setting a root password for an unrelated reason re-opens a root login on a connector-facing port silently — no config change, no firewall change, no alert — and makes §7.1's backlog of authenticated privilege-escalation and 2FA-bypass issues reachable in the same moment.

No CVSS is computed, consistent with VLN-010 and VLN-053.


7.1 The pre-auth question — RESOLVED 2026-09-08

This was the item that could have made the finding Critical regardless of the locked account, because a defect reached before authentication does not care that root cannot log in. It was checked against the vendor's own advisory list rather than answered from memory.

Result: no pre-authentication vulnerability is published against 2.621. Every advisory fixed in a later release requires an authenticated Webmin session or valid credentials:

Fixed in Issue Pre-auth?
2.653 Unprivileged users can perform privileged actions (DHCPd, MySQL, PostgreSQL, Nginx, Samba, Squid) No — needs a limited Webmin login
2.652 SSRF in Upload/Download and File Manager No — needs module access
2.641 Stored XSS in System and Server Status (CVE-2026-22678) No — needs template-creation rights
2.640 Privilege escalation via Help; 2FA bypass via basic auth (CVE-2026-42210, CVE-2026-56022); XSS via SVG email (CVE-2026-49102); email attachment overwrite (CVE-2026-49103) No — all need valid credentials

So the Critical trigger does not fire, and §7 stands at Medium.

Two things this does not license:

  • "No published pre-auth CVE" is not "no pre-auth surface." Webmin's history includes pre-authentication remote code execution, and this is an unauthenticated network-facing Perl web server running as root. The absence of a current advisory is a snapshot, not a property. This row should be re-checked whenever Webmin publishes.
  • 2.621 is behind by at least four security releases — 2.640, 2.641, 2.652 and 2.653 all carry fixes. On CEDAR none is reachable, because nobody can authenticate (§6.2). On any host where a Webmin login is usable, that list is live, and it includes privilege escalation and a 2FA bypass. See §9 for MAPLE, which is unmeasured.

7.2 The mitigating factor is a state, not a control

This is the part that keeps the rating at Medium rather than Low.

Nothing about Webmin's configuration prevents authentication. miniserv.conf still delegates to Unix/PAM, and the sole account is still root. The login fails for exactly one reason: /etc/shadow currently has no usable password for that account.

That is a state of a different subsystem, not a control on this one. Setting a root password — during a recovery procedure, a vendor support instruction, a console rescue, an imaging change — silently re-opens a root login on a connector-facing port, with:

  • no change to Webmin's configuration, so nothing in miniserv.conf review would show it,
  • no change to the firewall, so nothing in a rule audit would show it,
  • no alert, because nothing is watching for it, and
  • the §7.1 backlog of authenticated privilege-escalation and 2FA-bypass issues becoming reachable at the same instant.

"Safe because root happens to be locked" is a materially weaker assurance than "safe because Webmin cannot authenticate that way", and only the second is a control. The remediation in §8 converts the first into the second — which is why "it is already effectively unreachable" is not a reason to skip it.


8. Proposed remediation — NOT implemented

The cheapest option is also the most complete, which is unusual and worth taking.

Option A — remove the rule (recommended). Delete the 10000/tcp rich rule from 10.8.0.0/28 on both hosts. Administration continues unchanged via the SSH tunnel in §4.1, because that path arrives on loopback. This removes the entire exposure at the cost of nothing, and needs no Webmin change, no restart and no credential handling.

Option B — bind to loopback. Set bind=127.0.0.1 in miniserv.conf and restart Webmin, so the listener is not on 0.0.0.0 even if a firewall rule returns. Complements A; does not replace it.

No consumer for Webmin exists anywhere in the repository

Searched 2026-09-08 across soc-backend, status-backend and security-backend: nothing references port 10000, or Webmin at all. The backends do use the connector — soc-backend reads CEDAR's Elasticsearch (:9200) and MAPLE's Prometheus (:9090), and all three SSH to collect metrics — so the connector rules are not uniformly residue. Webmin's is. Recorded as a governance pattern in GOV-038.

This does not prove nobody uses it — a consumer could live outside this repo. It does mean no code depends on it, which is what makes Option C a low-risk change rather than a gamble.

Option C — disable Webmin entirely. This is now the recommended action, and three independent lines of evidence support it.

  1. Nobody can log in. The sole account is root, it delegates to Unix auth, and root is locked on both hosts (§6.2, §6.3).
  2. Nothing in the repository consumes it. No reference to port 10000, or to Webmin, in soc-backend, status-backend or security-backend — while the other connector rules do have consumers, so this is a specific result rather than a blanket one (§8.1 note above, and GOV-038).
  3. Nobody has logged in. /var/webmin/miniserv.log on CEDAR contains three entries, all the author's probes, all 401 (§2).

systemctl disable --now webmin removes the service and its entire pre-authentication surface — which, given (1), is the only surface left. It also converts §7.2's state into an actual control: with the service gone, setting a root password later cannot silently re-open anything.

8.2 MAPLE has no Webmin log at all, and that is not the same as no logins

MAPLE's log was read rather than assumed from CEDAR's, and the result is ambiguous rather than reassuring:

# sudo tail -50 /var/webmin/miniserv.log      [on MAPLE]
tail: cannot open '/var/webmin/miniserv.log' for reading: No such file or directory

An absent log file is not an absent access record. Three states produce it, and they are not equivalent:

State What it would mean
a Webmin has never served a request The file is created on first request. Ground (3) holds on MAPLE, more strongly than on CEDAR
b logfile= in miniserv.conf points elsewhere The record exists and was looked for in the wrong place. Says nothing either way
c Logging is disabled There would be no record of a login even if one happened — and a root-capable service with no audit trail is a worse position than CEDAR's, not a better one

CEDAR's default path was confirmed empirically — the author's own probes appeared in it. That is evidence about CEDAR and none about MAPLE, whose miniserv.conf remains unread (§9). Treating (a) as established because it is the comfortable reading would be the §6.3 error a third time.

It is settled by one command, which also closes the outstanding miniserv.conf item for MAPLE:

sudo grep -E 'log' /etc/webmin/miniserv.conf

This does not block the remediation. Grounds (1) nobody can log in and (2) nothing in the repo consumes port 10000 are both measured on MAPLE and are the load-bearing ones. Ground (3) was corroborative. So Option C stands on MAPLE — on two grounds rather than three, which is worth stating plainly rather than letting three-grounds language carry over from CEDAR.

If the answer turns out to be (c), it strengthens the case rather than weakening it: disabling removes a root-owned listener that keeps no record of who reached it.

MAPLE is now measured and matches (§6.3), so Option C applies equally there — with the caveat that MAPLE is the Wazuh manager, so confirm against its own miniserv.log before disabling rather than reusing CEDAR's answer.

Do not treat adding allow= in miniserv.conf as the fix. It adds a second layer, which is an improvement, but it leaves a root-capable listener exposed to the connector and solves a problem that Option A deletes.

Sequencing note. Unlike VLN-053, none of this affects an ingestion path: Webmin writes nothing and nothing depends on it. A and B can be done in a normal change window.


9. Open items

  • ~~Whether Webmin 2.621 carries a known pre-authentication vulnerability~~ — resolved 2026-09-08 against the vendor advisory list: none published (§7.1). Re-check when Webmin publishes; absence of a current advisory is a snapshot, not a property.
  • Webmin 2.621 is behind by at least four security releases (2.640, 2.641, 2.652, 2.653). Unreachable on CEDAR while root is locked; live on any host with a usable Webmin login. Patch currency is a separate decision from the exposure and is not tracked here.
  • ~~Whether the single root account delegates to Unix auth or is disabled~~ — resolved 2026-09-08: it is x, Unix/PAM (§6.1). The Webmin login is the system root password.
  • Whether root has a usable password in /etc/shadowsudo passwd -S root. This is now the deciding input for §7: L (locked) makes the login unusable despite Unix auth and drops the practical exposure; P confirms a guessable root login on the connector origin. Not checked, not assumed.
  • ~~MAPLE's miniserv.users~~ — measured 2026-09-08: root:x, and passwd -S root returns LK (§6.3). MAPLE matches CEDAR on all three facts and is now rated Medium alongside it.
  • MAPLE's miniserv.conf — §6's TLS and lockout settings are CEDAR's, and MAPLE's logfile=/logging directives are unread, which is what leaves §8.2 ambiguous. One grep closes both.
  • ~~Whether anyone actually uses it~~ — answered 2026-09-08 (§8.1): the log holds only the author's three probes, all 401. No successful authentication is recorded. Rotated logs were not checked, so this is "no logins in the current log", not "no logins ever".
  • Whether an unauthenticated GET rewrites miniserv.conf (§2). Resolve from the same log, not by repeating the probe.
  • firewall-cmd --list-all-zones on both hosts. Only the drop zone is active, but a second zone carrying rules would not appear in --list-all.
  • MAPLE's miniserv.conf was not read. §6 is CEDAR's. Same package and version, so the posture is probably identical — probably is not measured.