[Bugcrowd] JSM customers can delete any approval

Description

I found that JSM customers can delete any approval from the JSM project. If JSM portal allows customers to self sign up (the default and commonly used configuration), anyone can sign up and delete approvals. The only requirement is that the attacker must specify id of the approval to delete, but it is and integer value and can be enumerated. The app allows to use approvals in JSM portal, so the scenario is actual.

Steps to reproduce:

Part 1. Configuration

  1. Log in as admin, enable Jira Service Management if it is not enabled

  2. On the left-side panel click Apps -> Approval Path

  3. Go to Settings -> General and enable Allow manual initiation of approvals

  4. Go to Definitions

  5. Click Create

  6. Set any name

  7. Select the JSM project in Space

  8. Enable Available for JSM customers and Can be started by JSM customers

  9. Click Add step -> and any step

  10. Click Save definition

  11. Using Jira UI create a ticket in the JSM project (as a target to get a title of the issue)

  12. Open the created issue

  13. On the right-side panel expand Approval Path

  14. On New tab click Start to start an approval

  15. Go to requests history and find there a request to POST https://app.approval-path.com/connect/jira/create, get the approvalId value from the response

  16. Also, get a request to https://app.approval-path.com/connect/jira/rest/reference/approvals?collectionId=... and get the collection id parameter from the url. It is a project id, JSM users can get it in the JSM portal

Part 2. The vulnerability

  1. Go to https://<INSTANCE>.atlassian.net/servicedesk in an incognito browser window and sign up

  2. Confirm email to complete sign up

  3. Go to https://<INSTANCE>.atlassian.net/plugins/servlet/ac/ovh.atlassianinc.approval-path.jira/approval-dialog?classifier=json&project.id=<PROJECT_ID> with the collection id from step 16 of part 1 and get the url value from the response

  4. Send the request below with the value from the previous step:

POST /connect/JIRA/api/atlassian-connect-app HTTP/2Host: app.approval-path.comContent-Type: application/jsonContent-Length: 1236 {"url":"<URL>"}

Get the token value from the response. Send the request below with the JWT token and the id of the approval:

DELETE /connect/jira/delete/<APPROVAL_ID>?jwt=<TOKEN> HTTP/2Host: app.approval-path.com

Check that the approval was deleted.

Activity

Piotr Haraburda 28 January 2026, 12:18

@Adam Lipiński The issue was caused by a change made in

. I just rolled this back so there should be no issues on qa now.

Adam Lipiński 28 January 2026, 12:15

According to @Igor Hercer the issue with the GET /connect/jira/rest/reference/approvals endpoint returning approvals details to JSM customer is caused by changes from other task, by @Piotr Haraburda.

That makes this task ready to be merged as we’ve gone through the other endpoints with Igor on a call and confirmed they are working as expected.


@Piotr Haraburda could you let me know which task causes the issue with GET /connect/jira/rest/reference/approvals endpoint? So I will make sure to check this again when testing.

Adam Lipiński 26 January 2026, 18:52

@Igor Hercer The test results are below:

Not intended responses

ApprovalsListRestController (/connect/jira/rest, /connect/confluence/rest)

  1. GET /reference/approvals - Get reference approvals
    - Uses flag to determine view permissions

The above endpoint used with token generated from JSM customer (as described in repro steps) returned me 200 OK and list of all approvals from a project. Also checked this on PROD and on PROD it returns 401 Unauthorized.

Responses I am not sure about:

DefinitionRestController (/connect/jira/rest/definition, /connect/confluence/rest/definition)

  1. GET /reference - Get reference definitions
    - Filters definitions by visibleToJsmUsers and canBeStartedByJsmUsers for JSM customers

Here I am always getting 500 Internal Server Error, I am not sure if this is okay but I might be doing something wrong. I am adding something like this to the request after the token value: &definition-ids=<id1>%2C<id2>%2C<id3>

ApprovalsBulkActionsController (/connect/jira/bulk, /connect/confluence/bulk)

  1. DELETE /delete - Bulk delete approvals
    - Blocks all JSM customers ("No access")

  2. PATCH /archive - Bulk archive approvals
    - Blocks all JSM customers ("No access")

Response to the above requests was 403 Forbidden with “Missing CSRF token” message.

Seems ok but please confirm that this is intended.

ApprovalRestController (/connect/jira, /connect/confluence)

  1. POST /create - Create approval
    - JSM customers can start approvals (bypasses canStartApproval check)
    - Sets startedByJSMCustomer and canParametrize=false for JSM customers

  2. POST /action - Submit approval action (approve/reject)
    - Blocks JSM customers if approval has availableForJSMCustomers=false

Two requests above I didn’t test with the token as I am not sure how exactly do this - how to pass additional info, e.g. issueId etc.. Though I tested starting approvals and giving actions manually on JSM portal and I am not seeing any issues. :check_mark:

Responses I can confirm are correct:

DefinitionRestController (/connect/jira/rest/definition, /connect/confluence/rest/definition)

  1. GET /{id} - Get definition by ID (view definition)
    - JSM customers skip checkAccess, but are blocked if definition has availableForJSMCustomers=false

Response was either definition details for available ones or “No access” for not available ones.

ApprovalRestController (/connect/jira, /connect/confluence)

  1. DELETE /delete/{id} - Delete approval
    - Blocks all JSM customers ("No access")

  2. GET /get-users-for-notification/{id} - Get users for notification
    - Blocks all JSM customers ("No access")

  3. PATCH /archive/{id} - Archive approval
    - Blocks all JSM customers ("No access")

Response was “No access” for these.


If you want we can get on a call tomorrow to check the responses I am not sure about together.

Igor Hercer 22 January 2026, 18:19

Make sure that correct permissions are applied for JSM user after these changes.

DefinitionRestController (/connect/jira/rest/definition, /connect/confluence/rest/definition)

  1. GET /{id} - Get definition by ID (view definition)
    - JSM customers skip checkAccess, but are blocked if definition has availableForJSMCustomers=false

  2. GET /reference - Get reference definitions
    - Filters definitions by visibleToJsmUsers and canBeStartedByJsmUsers for JSM customers

ApprovalsListRestController (/connect/jira/rest, /connect/confluence/rest)

  1. GET /reference/approvals - Get reference approvals
    - Uses flag to determine view permissions

ApprovalRestController (/connect/jira, /connect/confluence)

  1. POST /create - Create approval
    - JSM customers can start approvals (bypasses canStartApproval check)
    - Sets startedByJSMCustomer and canParametrize=false for JSM customers

  2. POST /action - Submit approval action (approve/reject)
    - Blocks JSM customers if approval has availableForJSMCustomers=false

  3. DELETE /delete/{id} - Delete approval
    - Blocks all JSM customers ("No access")

  4. GET /get-users-for-notification/{id} - Get users for notification
    - Blocks all JSM customers ("No access")

  5. PATCH /archive/{id} - Archive approval
    - Blocks all JSM customers ("No access")

ApprovalsBulkActionsController (/connect/jira/bulk, /connect/confluence/bulk)

  1. DELETE /delete - Bulk delete approvals
    - Blocks all JSM customers ("No access")

  2. PATCH /archive - Bulk archive approvals
    - Blocks all JSM customers ("No access")

Adam Lipiński 20 January 2026, 18:42

@Igor Hercer This issue still occur exactly as before, I can still delete any approval from JSM project using customer’s token.

Adam Lipiński 15 January 2026, 14:23

The issue has been successfully reproduced by QA with provided steps.

I was able to delete an approval using token generated from account that didn’t even create any query on the portal.