
OPNsense 26.7.6 - High - Remote - Privilege leftover - UidField uid 0
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · opnsense-uidfield-system-uid0
Class: Privilege leftover Reach: Remote
OPNsense core 26.7.6 (a842fe48) - opnsense.org
Delegated page-system-usermanager two-steps scope=system then uid=0. UidField::setValue auto-assigns 2000+ only while scope is not system. setNodes applies uid before scope, so one add cannot stamp 0. The second POST can. auth sync user then pw useradd -o -u 0 with home /root and group wheel. Authorized keys land in /root/.ssh/authorized_keys. Privilege is System: Access: Management, not page-all.
| ID | no CVE yet |
| Class | Privilege leftover |
| Reach | Remote (authenticated WebGUI / Local API key) |
| CWE | CWE-269 / CWE-284 |
| CVSS | High: 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Product | OPNsense core (Deciso B.V.) |
| Affected | OPNsense core 26.7.6 (a842fe48c21288d11a422cb944678e8eb308becf) UidField / user-manager |
| Auth | WebGUI session or Local API key with page-system-usermanager |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
I pinned tag 26.7.6 "Xenial Xenops". The lab is a PHP gadget of the pinned UidField::setValue plus local_user_set, loopback identity 127.0.0.1:18810. stable/26.7 reverted the UID-0 write as ea4f01fe on 2026-10-09. That revert is not this pin. No GHSA.
| Method | Sink | Privilege |
|---|---|---|
two-step add scope=system then set uid=0 then auth sync user | pin UidField::setValue then stub pw useradd -o -u 0 (auth.inc:345-397) | Integrity (lab-proven): second Unix UID 0, home /root, group wheel. Lab: after-add=2000 after-set=0 pw-o-u0=yes. |
| same set + authorizedkeys | file_put_contents /root/.ssh/authorized_keys (auth.inc:407-416) | Integrity (lab-proven): witness in /root/.ssh/authorized_keys. |
SSH as that name if sshd is on (AllowGroups wheel; PermitRootLogin does not apply to a non-root username) | sshd | Recon + integrity (inferred): login as the new wheel name, read /root. Gadget did not start sshd. |
same POSTs with scope=user uid=0 | UidField auto-assign 2000+ | Negative (lab-proven): uid stays 2000. scope-user-uid0-ignored=yes. |
set stock root uuid uid=80 | pw usermod -u 80 | Integrity + availability (inferred): move stock root off UID 0. Gadget did not usermod root. |
set root uuid name=hax + scope=user | rename check skipped; auth sync user on the new name | Integrity (inferred): system user rename the 26.7.6 check was meant to stop. |
Lab-proven vs inferred: two-step UID 0, pw useradd -o -u 0, keys path, and scope=user ignore are lab SUCCESS. Live sshd accept and stock-root usermod/rename are inferred. Gadget, not a full OPNsense VM.
Requires: WebGUI session or Local API key with page-system-usermanager. CSRF on the session path. Not page-all. Default config.xml.sample only grants page-all to group admins.
| Surface | Lab |
|---|---|
POST /api/auth/user/* without page-system-usermanager | ACL closed |
user-config-readonly | save() still throwReadOnly() |
| CSV upload | strips uid/scope |
| CVE-2026-44194 email-as-shell | mwexecf %s + email regex |
| Password page | session-bound |
page-all doing the same POST | changelog feature on this pin |
| Unauth | closed |
Unix su with * in master.passwd | GUI hash stays in config.xml unless installer force |
No unauth. No page-all required. 26.7.6 presented chosen UID for system-scope users as an admin feature. The unmatched walk is a delegated user-manager without page-all.
cd lab
./run.sh
Loopback 127.0.0.1:18810. Compose project opnsense-uidfield-system-uid0. Image from pin 26.7.6. Witness OPNSENSE-UIDFIELD-SYSTEM-UID0-WITNESS. Last line:
SUCCESS opnsense-uidfield-system-uid0 two-step-uid=0 scope-user-uid0-ignored=yes pw-o-u0=yes keys=/root/.ssh/authorized_keys OPNSENSE-UIDFIELD-SYSTEM-UID0-WITNESS
Reject UID 0 (and colliding service UIDs) unless the caller is a full admin. Apply scope before uid in setNodes, or refuse a POST that flips both. Keep the 26.7.6 rename check on the pre-setNodes scope, not the posted one. ea4f01fe later reverted the UID-0 write on stable/26.7; that commit is not this pin.
a842fe48c21288d11a422cb944678e8eb308becfUidField.phpauth.inc local_user_setea4f01fe on stable/26.7