# [Vertical Privilege Escalation] User can Unapproved any Approved Translation at [/translations/unapprove/]

Logic error in Pontoon's unapprove view let any logged-in user unapprove any approved translation by supplying its ID.

- Payout: hidden
- Severity: medium
- Program: Mozilla
- Found by: adilnbabras
- Disclosed: 2026-04-10
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/3020021
- Library page: https://bugbountylibrary.com/r/h1%3A3020021
- Tags: area:web domain:web impact:integrity kind:bounty platform:hackerone sev:medium technique:source-review vuln:access-control vuln:business-logic vuln:privilege-escalation

**Target:** POST /translations/unapprove/ endpoint
**Root cause:** The authorization check uses `or translation.approved` in the deny condition, so any approved translation makes the guard false and skips the privilege check entirely.
**Steps:**
1. Log in and open any team/project/resource string page
2. Capture `/get-history/` response to obtain the approved translation ID
3. Send `POST /translations/unapprove/` with `translation=<id>&paths[]=LC_MESSAGES/amo.po` and valid CSRF token
4. Observe 200 OK and translation now unapproved
**How found:** Researcher noticed the UI blocked unapprove for non-privileged users, then read the view source and spotted the inverted `or translation.approved` condition in the guard.
**Exploitation:** Authenticated low-privilege user extracts an approved translation ID from the get-history endpoint and posts it to /translations/unapprove/, bypassing the privilege check to revert approval state.
**Insight:** When an authorization guard is a negated OR-chain, check each clause for a condition that is trivially true for the target object (like `approved`), which collapses the whole check.
