NAV Navbar

Webhooks

This functionality is currently in beta and only available to selected customers. Please email your HackerOne Program Manager if you want to participate in this beta.

With webhooks you can build your own real-time integrations that subscribe to certain report and program events on HackerOne. When one of those events is triggered, we'll send an HTTP POST payload to the webhook's configured URL. Webhooks can be used to update an external issue tracker, trigger a notification system, update a reports data backup, or even trigger provisioning a user account.

Webhooks can be created on a program level, and are bound to the permissions of the user that creates the webhook. Once configured, the webhook will be triggered each time one or more subscribed events occur.

Events

When configuring a webhook, you can choose which events you would like to receive payloads for. Subscribing to the specific events you plan on handling is useful for limiting the number of HTTP requests to your server. Each event corresponds to a certain set of actions that can happen to your program and reports. For example, if you subscribe to the report_created event you'll receive an HTTP request with a detailed payload every time a hacker submits a new vulnerability report to your program.

The available events are:

Event Description
report_agreed_on_going_public This event triggers when a report is agreed to be publicly disclosed.
report_bounty_awarded This event triggers when a hacker is awarded a bounty as a result of their report.
report_bounty_suggested This event triggers when a bounty is suggested against a report.
report_closed_as_duplicate This event triggers when a report is closed as a duplicate of another report.
report_closed_as_informative This event triggers when a report is closed as informative.
report_closed_as_spam This event triggers when a report is closed as spam.
report_closed_as_not_applicable This event triggers when a report is closed as not applicable.
report_comment_created This event triggers each time a comment is created on a report.
report_comments_closed This event triggers when a report is locked.
report_created This event triggers each time a new vulnerability report is created.
report_needs_more_info This event triggers when a report is requiring new information.
report_new This event triggers when a report has changed which requires program input.
report_reopened This event triggers when a report is reopened.
report_resolved This event triggers when a report is resolved.
report_triaged This event triggers when a report is triaged.
report_group_assigned This event triggers when a report is assigned to another group.
report_manually_disclosed This event triggers when a report is manually disclosed.
report_not_eligible_for_bounty This event triggers when a report is marked as not eligible for bounty.
report_became_public This event triggers when a report is made publicly accessible.
report_undisclosed This event triggers when a report is undisclosed.
report_swag_awarded This event triggers when a hacker is rewarded swag as a result of their report.
report_user_assigned This event triggers when a user is assigned to a report.
program_hacker_joined Applies to private programs only. This event triggers each time a hacker joins your program.
program_hacker_left Applies to private programs only. This event triggers each time a hacker leaves your program.

Payloads

Each webhook event has a predefined payload format with the relevant event information. Each payload contains the relevant report information, and information about the reporter.

Delivery headers

Every HTTP request made to your webhooks' configured URL contains several special headers:

Header
Description
X-H1-Event The name of the event that triggered the delivery.
X-H1-Delivery A GUID to uniquely identify the delivery
X-H1-Signature The HMAC hex digest of the request body.

If a secret is specified the HMAC hex digest is generated based on the request body using the SHA256 hash function and the secret as the HMAC key.
If no secret is specified the HMAC hex digest is generated based solely on the request body using the SHA256 hash function.

See the validating payloads section for more info.

Example delivery

{
  "data": {
    "activity": {
      "type": "activity-bug-filed",
      "id": "1337",
      "attributes": {
        "message": "",
        "created_at": "2020-02-25T08:05:21.674Z",
        "updated_at": "2020-02-25T08:05:21.674Z",
        "internal": false
      },
      "relationships": {
        "actor": {
          "data": {
            "id": "1",
            "type": "user",
            "attributes": {
              "username": "hacker",
              "name": "Hacker One",
              "disabled": false,
              "created_at": "2019-08-01T13:53:04.239Z",
              "profile_picture": {
                "62x62": "/assets/avatars/default.png",
                "82x82": "/assets/avatars/default.png",
                "110x110": "/assets/avatars/default.png",
                "260x260": "/assets/avatars/default.png"
              },
              "signal": null,
              "impact": null,
              "reputation": 107,
              "bio": null,
              "website": null,
              "location": null,
              "hackerone_triager": null
            }
          }
        }
      }
    },
    "report": {
      "id": "548",
      "type": "report",
      "attributes": {
        "title": "Critical vulnerability!",
        "state": "new",
        "created_at": "2020-02-25T08:05:21.405Z",
        "vulnerability_information": "## Summary:\n[add summary of the vulnerability]\n\n## Steps To Reproduce:\n[add details for how we can reproduce the issue]\n\n  1. [add step]\n  1. [add step]\n  1. [add step]\n\n## Supporting Material/References:\n[list any additional material (e.g. screenshots, logs, etc.)]\n\n  * [attachment / reference]\n\n## Impact\n\nThe trouble i've seen",
        "triaged_at": null,
        "closed_at": null,
        "last_reporter_activity_at": "2020-02-25T08:05:21.674Z",
        "first_program_activity_at": "2020-02-25T08:05:21.674Z",
        "last_program_activity_at": "2020-02-25T08:05:21.674Z",
        "bounty_awarded_at": null,
        "swag_awarded_at": null,
        "disclosed_at": null,
        "reporter_agreed_on_going_public_at": null,
        "last_public_activity_at": "2020-02-25T08:05:21.674Z",
        "last_activity_at": "2020-02-25T08:11:20.699Z",
        "source": null
      },
      "relationships": {
        "reporter": {
          "data": {
            "id": "1",
            "type": "user",
            "attributes": {
              "username": "hacker",
              "name": "HackerOne",
              "disabled": false,
              "created_at": "2019-08-01T13:53:04.239Z",
              "profile_picture": {
                "62x62": "/assets/avatars/default.png",
                "82x82": "/assets/avatars/default.png",
                "110x110": "/assets/avatars/default.png",
                "260x260": "/assets/avatars/default.png"
              },
              "signal": null,
              "impact": null,
              "reputation": null,
              "bio": null,
              "website": "http://hackerone.com",
              "location": null,
              "hackerone_triager": null
            }
          }
        },
        "severity": {
          "data": {
            "id": "1",
            "type": "severity",
            "attributes": {
              "rating": "low",
              "author_type": "User",
              "user_id": "1",
              "created_at": "2020-02-25T08:05:21.405Z"
            }
          }
        }
      }
    }
  }
}

Validating payloads from HackerOne

To validate that a request originated from HackerOne, we suggest providing a secret for all webhooks set up on our platform.

This secret is used to generate the X-H1-Signature header, containing the HMAC hexdigest of the request body signed with the provided secret as the key. If the secret is not provided, the signature is generated with an empty string key ('').

To verify the validity of any given request, the goal is to generate a hash of the body on your end-service using the shared secret, and validating this against the given X-H1-SIGNATURE header. Supposing a simple endpoint is listening to our incoming webhooks; our requests can be verified by hash validation against our signature like so:


Python:

Assuming that the request is a request with an accessible json format body attribute:

import json
import hmac

def validate_request(request, secret, signature):
    [ _, digest ] = signature.split('=')

    body = str(json.dumps(request['body']))

    generated_digest = hmac.new(secret.encode(), body.encode(), "sha256").hexdigest()

    return hmac.compare_digest(digest, generated_digest)

Ruby:

A similar implementation in Ruby (making use of Racks secure_compare constant time comparator):

def validate_request(body, secret, signature)
  _, digest = signature.split("=")
  generated_digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, body)
  return halt 500, "Invalid signature!" unless Rack::Utils.secure_compare(generated_digest, digest)
end

Although implementations may differ, and the above are only examples for how it could be achieved, there are two key points to implementation: