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
rootand 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
MAPLE
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 it — gpus-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:
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=ordeny=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=60is 60 seconds, afterblockhost_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:
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:
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:
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.confreview 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.
- Nobody can log in. The sole account is
root, it delegates to Unix auth, androotis locked on both hosts (§6.2, §6.3). - Nothing in the repository consumes it. No reference to port 10000, or to
Webmin, in
soc-backend,status-backendorsecurity-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). - Nobody has logged in.
/var/webmin/miniserv.logon CEDAR contains three entries, all the author's probes, all401(§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:
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
rootis 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
rootaccount delegates to Unix auth or is disabled~~ — resolved 2026-09-08: it isx, Unix/PAM (§6.1). The Webmin login is the system root password. - Whether
roothas a usable password in/etc/shadow—sudo 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;Pconfirms a guessable root login on the connector origin. Not checked, not assumed. - ~~MAPLE's
miniserv.users~~ — measured 2026-09-08:root:x, andpasswd -S rootreturnsLK(§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'slogfile=/logging directives are unread, which is what leaves §8.2 ambiguous. Onegrepcloses 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
GETrewritesminiserv.conf(§2). Resolve from the same log, not by repeating the probe. firewall-cmd --list-all-zoneson both hosts. Only thedropzone is active, but a second zone carrying rules would not appear in--list-all.- MAPLE's
miniserv.confwas not read. §6 is CEDAR's. Same package and version, so the posture is probably identical — probably is not measured.