Django REST framework: TokenProxy.delete() reports success and revokes nothing
Published Oct 21, 2026 · Updated Nov 3, 2026
Original summary
Normalized public record · Updated Nov 3, 2026
Django REST framework: TokenProxy.delete() reports success and revokes nothing
Publisher and source text is retained separately from QFinch interpretation.
QFinch assessment
Deleting an authentication token through TokenProxy silently deletes nothing. The call raises no exception and reports success, the database row survives, and the token keeps authenticating. Any application, admin integration or operational script that revokes credentials by calling .delete() on a TokenProxy instance believes it has revoked a token that is still live.
Potential impact
Failed credential revocation. An operator who revokes a token through a TokenProxy instance, and receives no error, leaves a live credential in circulation indefinitely, because DRF auth tokens do not expire on their own. Whoever holds that token benefits: a departed employee, a rotated integration, a device believed to be deprovisioned, or an attacker whose access was thought to have been cut during incident response. No untrusted input reaches this code path, which is why the vector is scored AC:H. Exploitation depends on the deployment revoking through the proxy, which is a natural thing to do given TokenProxy is the model registered in the admin and the one most code will reach for. Any deployment on 3.12.0 or later that revokes tokens outside DRF's own TokenAdmin.deletemodel should audit whether its revocations took effect.
Technical context
TokenProxy overrides pk to return the user id (restframework/authtoken/models.py:49-63): The concrete Token model keys on key, not on an integer id. Model.delete() builds its delete query from pk, so it emits: That matches a user id against the 40-character key column. Nothing matches, nothing raises, and the call returns (0, {'authtoken.TokenProxy': 0}). DRF already ships two workarounds for this same identity mismatch instead of a fix. In restframework/authtoken/admin.py, TokenAdmin.deletemodel re-fetches the concrete row: and TokenAdmin sets actions = None with the comment "Actions not compatible with mapped IDs" (admin.py:50-53). The shipped admin path is therefore safe, and every other caller of TokenProxy.delete() is not. Nothing in the API signals the difference. TokenProxy was added by e2bd3b6a (PR 7341, "Adjusted token admin to map to user ID"), first released in 3.12.0. A fix would drop the pk override, or give TokenProxy a delete() that operates on the concrete row, or raise instead of silently reporting zero deletions.
Evidence: public source recordsAffected products
| Affected package, product or range | Fix status |
|---|---|
| Consult the referenced vendor advisory for affected versions. | Consult source advisory |
Matching a version is only one part of assessing exposure. QFinch has not assessed your environment on this public page.
Remediation
Apply the vendor-supported fixed release or mitigation, then verify the affected component is no longer reachable.
- Confirm the affected product and reachable code path exist in your environment.
- Apply the vendor-supported patch or mitigation from the primary advisory.
- Rescan the exact deployed revision and retain verification evidence.
Evidence coverage
- SSVC priority
- MEDIUM
- Confidence
- Not available
- Aliases
- None reported
Scores appear only when corresponding evidence exists. Missing data is never interpreted as zero risk.
Sources and record history
Record history
Published Oct 21, 2026 · Last refreshed Nov 3, 2026