# HackerOne

## Create Vuln from HackerOne Report

The purpose of this example is to create a new vulnerability immediately when a new report is submitted on HackerOne.

{% embed url="<https://youtu.be/lLhXPshWe1g>" %}

<figure><img src="https://372186556-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M8s1QY2Q6YTHB4a6DMu%2Fuploads%2Fkc9X7wmEZdl3JjjeKW0s%2FScreenshot%202025-06-24%20at%204.00.04%E2%80%AFpm.png?alt=media&#x26;token=5ac78ca0-1202-4062-9571-12e96088dcae" alt=""><figcaption></figcaption></figure>

This example Flow can be downloaded from our [Flows GitHub Repository](https://github.com/AttackForge/Flows) and [imported](#importing-exporting-flows) into your AttackForge.

**Initial Set Up**

* **HTTP Trigger**
  * **Method:** POST
  * **Authentication**: None
* **Secrets**:
  * h1\_webhook\_secret - your [HackerOne Webhook Secret](https://api.hackerone.com/webhooks/#webhooks)
  * hackerone\_api\_key - your [HackerOne API Key](https://api.hackerone.com/getting-started/#getting-started)
  * x\_user\_key - your [AttackForge Self-Service API token](https://support.attackforge.com/attackforge-enterprise/modules/self-service-restful-api/getting-started#accessing-the-restful-api).

**Action 1 - Get HackerOne Report**&#x20;

* **Method**: GET
* **URL**: <https://api.hackerone.com/v1/reports/{id}>
* **Headers**:
  * Key = Content-Type; Type = Value; Value = application/json
  * Key = Authorization; Type = Secret; Value = hackerone\_api\_key
* **Request Script**:

```javascript
// Validate HMAC
const h1Secret = secrets.h1_webhook_secret;
const h1Signature = String.replace(data.headers['X-H1-Signature'], "SHA256=", '');
const payloadHMAC = String.toLowerCase(String.hmac(data.body, h1Secret, "SHA256", "base16"));

if (h1Signature !== payloadHMAC) {
  Logger.info('h1Signature: ' + h1Signature);
  Logger.info('hmac: ' + payloadHMAC);

  return {
    decision: {
      status: 'abort',
      message: 'Invalid HMAC',
    }
  };
}

if (data.jsonBody?.data?.report?.id) {
  return {
    decision: {
      status: 'continue',
      message: 'Fetching HackerOne Report',
    },
    request: {
      url: 'https://api.hackerone.com/v1/reports/' + data.jsonBody.data.report.id
    }
  };
}
else {
  return {
    decision: {
      status: 'abort',
      message: 'Missing "data.report.id"',
    }
  };
}

```

* **Response Script**:

```javascript
let body;

if (response.headers['Content-Type'] === 'application/json; charset=utf-8') {
  body = JSON.parse(response.body);
}
else {
  return {
    decision: {
      status: 'abort',
      message: 'Content-Type is expected to be application/json; charset=utf-8'
    }
  };
}

if (response.statusCode === 200 && body?.data) {
  return {
    decision: {
      status: 'continue',
      message: 'Retrieved HackerOne Report'
    },
    data: {
      report: body.data
    }
  };
}
else {
  Logger.error(JSON.stringify(response));

  return {
    decision: { 
      status: 'abort',
      message: 'Failed retrieving HackerOne Report'
    },
  };
}
```

**Action 2 - Get CWE Details**&#x20;

* **Method**: GET
* **URL**: <https://cwe-api.mitre.org/api/v1/cwe/weakness/{id}>
* **Headers**:
  * Key = Content-Type; Type = Value; Value = application/json
* **Request Script**:

```javascript
let cweId = undefined;
if (data.report?.relationships?.weakness?.data?.attributes?.external_id) {
  const cweField = data.report.relationships.weakness.data.attributes.external_id;

  if (String.startsWith(cweField, 'cwe-')) {
    cweId = String.replace(cweField, "cwe-", "");
  }
}

if (cweId) {
  return {
    decision: {
      status: 'continue',
      message: 'Fetching CWE [ ' + cweId + ' ] details',
    },
    request: {
      url: 'https://cwe-api.mitre.org/api/v1/cwe/weakness/' + cweId
    },
    data: {
      report: data.report
    }
  };
}
else {
  return {
    decision: {
      status: 'next',
      message: 'No CWE found. Skip fetching CWE details.',
    }
  };
}

```

* **Response Script**:

```javascript
let body;

if (response.headers['Content-Type'] === 'application/json; charset=UTF-8') {
  body = JSON.parse(response.body);
}
else {
  return {
    decision: {
      status: 'abort',
      message: 'Content-Type is expected to be application/json; charset=UTF-8'
    }
  };
}

if (response.statusCode === 200 && body?.Weaknesses?[0]) {
  return {
    decision: {
      status: 'continue',
      message: 'Retrieved CWE details'
    },
    data: {
      report: data.report,
      cwe: body?.Weaknesses[0]
    }
  };
}
else {
  Logger.error(JSON.stringify(response));

  return {
    decision: { 
      status: 'abort',
      message: 'Failed retrieving CWE details'
    },
  };
}
```

**Action 3 - Create Vulnerability**&#x20;

* **Method**: POST
* **URL**: <https://acme.attackforge.com/api/ss/vulnerability>
* **Headers**:
  * Key = Content-Type; Type = Value; Value = application/json
  * Key = X-SSAPI-KEY; Type = Secret; Value = x\_user\_key
* **Request Script**:

```javascript
if (data.report) {
  const report = data.report;
  const cwe = data.cwe;

  return {
    decision: {
      status: 'continue',
      message: 'Creating Vulnerability',
    },
    request: {
      body: buildRequestBody(report, cwe)
    },
    data: {}
  };
}
else {
  return {
    decision: {
      status: 'abort',
      message: 'Missing HackerOne Report',
    }
  };
}
  
function buildRequestBody (report, cwe) {
  const vuln = {
    projectId: "685500711d6a44e61f90db4e",
    title: "New Submission",
    affected_asset_name: "AttackForge-TEST H1B",
    priority: "Info",
    likelihood_of_exploitation: 1,
    description: "TBD",
    attack_scenario: "TBD",
    remediation_recommendation: "TBD",
    steps_to_reproduce: "TBD",
    tags: [
      'HackerOne',
      'H1'
    ],
    is_visible: true,
    custom_fields: []
  };

  if (cwe) {
    if (cwe.ID) {
      const name = cwe.ID;
      Array.push(vuln.tags, 'CWE-' + cwe.ID);
    }
    if (cwe.Name) {
      const name = cwe.Name;
      vuln.title = name;
    }
    if (cwe.Description) {
      let description = cwe.Description;
      vuln.description = formatVulnInfo(description);
    }
    if (cwe.ExtendedDescription) {
      let extendedDescription = cwe.ExtendedDescription;
      vuln.description = vuln.description + ' ' + formatVulnInfo(extendedDescription);      
    }
    if (cwe.BackgroundDetails) {
      const backgroundDetails = cwe.BackgroundDetails;
      vuln.attack_scenario = "";
      if (Array.isArray(backgroundDetails)) {
        for (let x = 0; x < backgroundDetails.length; x++) {
          const attackScenario = backgroundDetails[x];
          vuln.attack_scenario = vuln.attack_scenario + formatVulnInfo(attackScenario);
        }
      }
      else {
        vuln.attack_scenario = vuln.attack_scenario + formatVulnInfo(backgroundDetails);
      }
    }
    if (cwe.PotentialMitigations) {
      const potentialMitigations = cwe.PotentialMitigations;
      vuln.remediation_recommendation = "";
      if (Array.isArray(potentialMitigations)) {
        for (let x = 0; x < potentialMitigations.length; x++) {
          const mitigation = potentialMitigations[x];
          if (mitigation.Description) {
            vuln.remediation_recommendation = vuln.remediation_recommendation 
              + formatVulnInfo(mitigation.Description);
          } 
        }
      }
      else {
        if (potentialMitigations.Description) {
          vuln.remediation_recommendation = vuln.remediation_recommendation 
            + formatVulnInfo(potentialMitigations.Description);
        }
      }
    }
    if (report.attributes?.title && report.attributes.vulnerability_information) {
      vuln.steps_to_reproduce = '<p>' 
        + report.attributes.title + '</p><p>' 
        + formatVulnInfo(report.attributes.vulnerability_information) 
        + '</p>';
    }
  }
  else {
    if (report.attributes?.title) {
      vuln.title = report.attributes.title;
    }
    if (report.attributes?.vulnerability_information) {
      vuln.description = formatVulnInfo(report.attributes.vulnerability_information);
    }
  }

  if (report.id) {
    Array.push(vuln.custom_fields, {
      key: "hackerone_report_id",
      value: report.id
    });
    if (report.relationships?.program?.data?.attributes?.handle) {
      const handle = report.relationships.program.data.attributes.handle;
      Array.push(vuln.custom_fields, {
        key: "hackerone_report_url",
        value: 'https://hackerone.com/bugs?report_id=' + report.id + '&subject=' + handle
      });
    }
  }
  if (report.relationships?.severity?.data?.attributes) {
    const severity = report.relationships.severity.data.attributes;
    if (severity.rating === 'critical') {
      vuln.priority = 'Critical';
    }
    else if (severity.rating === 'high') {
      vuln.priority = 'High';
    }
    else if (severity.rating === 'medium') {
      vuln.priority = 'Medium';
    }
    else if (severity.rating === 'low') {
      vuln.priority = 'Low';
    }

    if (severity.score && severity.cvss_vector_string) {
      vuln.likelihood_of_exploitation = Number.parseInt(Math.ceil(severity.score));
      Array.push(vuln.tags, 'CVSSv3.1 Base Score: ' + severity.score);
      Array.push(vuln.tags, severity.cvss_vector_string);
    }
  }

  return vuln;
};

function formatVulnInfo (value) {
  if (String.startsWith(value, "\n\n")) {
    value = String.substring(value, 2);
  }
  else if (String.startsWith(value, "\n")) {
    value = String.substring(value, 1);
  }
  value = String.replaceAll(value, "\n\n", "<br/>");
  value = String.replaceAll(value, "\n", "<br/>");
  
  return value;
};
```

* **Response Script**:

```javascript
let body;

if (response.headers['Content-Type'] === 'application/json') {
  body = JSON.parse(response.body);
}
else {
  return {
    decision: {
      status: 'abort',
      message: 'Content-Type is expected to be application/json'
    }
  };
}

if (response.statusCode === 200 && body?.vulnerability?.vulnerability_id) {
  return {
    decision: {
      status: 'finish',
      message: 'Created Vulnerability'
    }
  };
}
else {
  Logger.error(JSON.stringify(response));

  return {
    decision: { 
      status: 'abort',
      message: 'Failed creating Vulnerability'
    },
  };
}
```
