Poweradmin: IDOR Broken Access Control in DNS Record Edit
Any authenticated Poweradmin user who owns at least one DNS zone can overwrite records in zones they have no access to, by sending a victim's record ID alongside their own zone ID in a crafted POST…

The problem
Poweradmin's record-edit flow in RecordManager::editRecord() checks zone ownership against a zid value from the POST body, but then applies the database write to a rid value also from the POST body. Nothing on the server ties the record ID back to the zone ID, so the permission gate and the write target completely different objects.
The backend SQL is WHERE id = ? with no zone column in the predicate, meaning any record in the entire database is reachable. An attacker with a single owned zone (zone id 3, for example) can overwrite content, type, ttl, and the disabled flag of any record in any other zone.
In a shared or multi-tenant install this is a full cross-tenant DNS takeover.
Proof of concept
A working proof-of-concept for this issue in poweradmin/poweradmin, with the exact payload below.
POST /zones/3/edit HTTP/1.1
Host: poweradmin.example.com
Cookie: PHPSESSID=<attacker-session>
Content-Type: application/x-www-form-urlencoded
_token=<valid-csrf-token>&serial=<current-soa-serial>&commit=1&record[5][rid]=5&record[5][zid]=3&record[5][name]=pwned&record[5][type]=A&record[5][content]=6.6.6.6&record[5][ttl]=3600&record[5][prio]=0
# record[5][rid]=5 -> victim's record (lives in zone 2, owned by admin)
# record[5][zid]=3 -> attacker's own zone (passes the ownership check)
# _token + serial -> attacker's own valid CSRF token and SOA serial; nothing looks anomalousThe root cause is a confused-deputy pattern (CWE-639, authorization bypass through user-controlled key). The ownership check reads $record['zid'] from the request, and the write reads $record['rid'] from the same request. Because neither value is validated against the other, the attacker can point them at different rows entirely.
The fix in commits 12651fa, 88f443d, and e021067 (released as v3.9.11 / v4.2.5) stops trusting the client-supplied zid. Instead, editRecord() now derives the real zone from the record ID on the server side using getZoneIdFromRecordId(), matching the approach already used by the delete path.
The hidden-field marker scheme added to the edit template also prevents submitting record rows that were not rendered by the server.
The fix
Upgrade to Poweradmin 3.9.11 (3.x LTS) or 4.2.5 (stable). Both releases bind record edits to the zone the record actually belongs to, server-side. No config changes are required; it is a drop-in upgrade. Custom themes that fork edit.html must be re-synced because zone saves now depend on new hidden marker fields added by the patch.
Reported by Saif Salah.
Related research
- high · 8.8Poweradmin: API Broken Access Control Allows Non-Admin to Reset Any User's Password
- high · 8.1Poweradmin OIDC sub Collation Bypass Account Takeover
- criticalCVE-2026-47156CVE-2026-47156: MantisBT SOAP API Authentication Bypass with Privilege Escalation
- criticalCVE-2026-27823CVE-2026-27823: EGroupware SmallPART Remote Code Execution via Auth Bypass and Path Traversal