---
title: "Defect Dojo"
description: "Import StackHawk scan findings into Defect Dojo for vulnerability management."
url: https://docs.stackhawk.com/integrations/workflows/defect-dojo/
---

# Defect Dojo

![Defect Dojo](https://docs.stackhawk.com/images/integrations/logos/defect-dojo.svg)

## Overview

StackHawk has contributed a custom parser to the Defect Dojo project. The parser is capable of importing [webhook](https://docs.stackhawk.com/integrations/workflows/webhook/) event JSON as findings into the Defect Dojo platform.

> **Warning:** This integration will require you to create and host a webhook consuming application, capable of feeding these webhook events to your Defect Dojo installation.

There are some example snippets below to assist you with your own webhook consuming application.

When you’re ready to set up your Defect Dojo integration, be sure to check out the guide to enable the [webhook](https://docs.stackhawk.com/integrations/workflows/webhook/) integration, and have your application’s webhook endpoint ready to go!

## Features

- HawkScan findings can be auto imported as Defect Dojo findings.
- Updates to scan results (re-imports) can auto close findings in Defect Dojo.

## Requirements

**StackHawk:**

- You must have a StackHawk account.
- *Your StackHawk Organization must belong to a plan with* The Webhook Integration *enabled*. [Contact StackHawk Support](https://docs.stackhawk.com/support/) to enable it.

**Defect Dojo:**

- You must have login permissions to the Defect Dojo workspace you wish to set up this workflow for.
- You must be on Defect Dojo version `2.8.0` or above.

## API References

Defect Dojo API references will be provided via the hosted [Defect Dojo demo application](https://demo.defectdojo.org/). Information about this demo site (including how to log in to it) is available on the [official Defect Dojo README](https://github.com/DefectDojo/django-DefectDojo#demo).

There are 2 important API operations provided by Defect Dojo that allow automatically importing scans via custom parsers.

- The [`import-scan` operation](https://demo.defectdojo.org/api/v2/oa3/swagger-ui/?docExpansion=none#/import-scan) is used for the initial import to an engagement.
- The [`reimport-scan` operation](https://demo.defectdojo.org/api/v2/oa3/swagger-ui/?docExpansion=none#/reimport-scan/reimport_scan_create) is used to add subsequent scans to an engagement / test in Defect Dojo.

To interact with the StackHawk parser, please specify the `scan_type` as `StackHawk HawkScan` for both operations.

> **Note:** Use *both* operations in your webhook consumer. The reimport operation has useful behavior associated with it, such as automatically closing resolved issues, allowing you to better track findings in Defect Dojo.

## Authenticating with Defect Dojo

You can find example documentation for authenticating to Defect Dojo on [the demo site](https://demo.defectdojo.org/api/key-v2).

When you’re ready to get your own API key for the Defect Dojo API, you can find personalized instructions at `<YOUR_DEFECT_DOJO_DOMAIN>/api/key-v2`.

## Guide

The Defect Dojo custom parser works on the webhook payload verbatim. No modifications are necessary. We *strongly* recommend saving the webhook payload contents as-is to a file for upload into Defect Dojo.

### Downloading the Webhook from StackHawk

These examples will showcase an endpoint (`/my-webhook`) downloading the contents of the StackHawk webhook payload to `stackhawk-webhook.json`.

**Tab: Kotlin + Spring Boot**

```kotlin
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import java.io.File

@PostMapping("/my-webhook")
fun receiveStackHawkWebhook(@RequestBody webhook: String) {
    File("stackhawk-webhook.json")
            .bufferedWriter()
            .use { out -> out.write(webhook) }
}
```

**Tab: Node.js + Express**

```javascript
const fs = require('fs');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));

app.post('/my-webhook', (request, response) => {
    request.pipe(fs.createWriteStream("stackhawk-webhook.json", {flags: 'a'}));

    response.sendStatus(200);
});
```

**Tab: Python + Flask**

```python
from flask import request

@app.route('/my-webhook', methods=['POST'])
def receiveStackHawkWebhook():
    with open("stackhawk-webhook.json") as fo:
        fo.write(request.json)
```

### Importing Webhook to Defect Dojo

These examples will demonstrate calling the Defect Dojo API with `stackhawk-webhook.json`, downloaded in the above example. The `filename` parameter should be the reference to the `stackhawk-webhook.json`.

**Tab: Kotlin + Spring Boot**

```kotlin
import org.springframework.core.io.ClassPathResource
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.http.client.MultipartBodyBuilder
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.BodyInserters
import org.springframework.web.reactive.function.client.WebClient
// You provide / declare this object.
import your.own.package.for.DefectDojoProperties

@Service
class DefectDojoService(
    private val webClient: WebClient,
    private val properties: DefectDojoProperties
) {

    fun uploadToDefectDojo(filename: String, isNewImport: Boolean) {
        val multipartBodyBuilder = MultipartBodyBuilder()

        multipartBodyBuilder.addTextValue("scan_type", "StackHawk HawkScan")

        multipartBodyBuilder.part("file", ClassPathResource(filename).file.readBytes())
            .header(HttpHeaders.CONTENT_DISPOSITION, "form-data; name=file; filename=$filename;")

        multipartBodyBuilder.addTextValue("product_name", "<YOUR_DEFECT_DOJO_PRODUCT_NAME>")
        multipartBodyBuilder.addTextValue("engagement_name", "<YOUR_DEFECT_DOJO_ENGAGEMENT_NAME>")

        // optional, used for `import-scan`
        multipartBodyBuilder.addTextValue("product_type_name", "<YOUR_DEFECT_DOJO_PRODUCT_TYPE_NAME>")

        // optional, used for `reimport-scan`
        multipartBodyBuilder.addTextValue("test_title", "<YOUR_DEFECT_DOJO_TEST_TITLE>")

        // Example available form options can be found @
        // https://demo.defectdojo.org/api/v2/oa3/swagger-ui/

        // determine if this is a new import or an existing one.
        val uri = if (isNewImport) {
            "/api/v2/import-scan/"
        } else {
            "/api/v2/reimport-scan/"
        }
        webClient.post()
            .uri(properties.domain + uri)
            .contentType(MediaType.MULTIPART_FORM_DATA)
            .header(HttpHeaders.AUTHORIZATION, "Token <YOUR_DEFECT_DOJO_API_KEY>")
            .body(BodyInserters.fromMultipartData(multipartBodyBuilder.build()))
            .retrieve()
    }

    private fun MultipartBodyBuilder.addTextValue(name: String, value: String) {
        part(name, value, MediaType.TEXT_PLAIN)
            .header(HttpHeaders.CONTENT_DISPOSITION, "form-data; name=$name;")
            .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
    }
}
```

**Tab: Node.js + Express**

```javascript
const fs = require('fs');

uploadToDefectDojo(filename, isNewImport) {
    const uri = isNewImport ? "/api/v2/import-scan/" : "/api/v2/reimport-scan/";
    const options = {
        method: "POST",
        url: defectDojoDomain + uri,
        port: 443,
        headers: {
            "Content-Type": "multipart/form-data",
            "Authorization": "Token <YOUR_DEFECT_DOJO_API_KEY>"
        },
        formData : {
            "file" : fs.createReadStream(filename),
            "scan_type": "StackHawk HawkScan",
            "product_name": "<YOUR_DEFECT_DOJO_PRODUCT_NAME>",
            "engagement_name": "<YOUR_DEFECT_DOJO_ENGAGEMENT_NAME>",

            // optional, used for `import-scan`
            "product_type_name": "<YOUR_DEFECT_DOJO_PRODUCT_TYPE_NAME>",

            // optional, used for `reimport-scan`
            "test_title": "<YOUR_DEFECT_DOJO_TEST_TITLE>"

            // Example available form options can be found @
            // https://demo.defectdojo.org/api/v2/oa3/swagger-ui/
        }
    };

    request(options, function (err, res, body) {
        if(err) console.log(err);
        console.log(body);
    });
}
```

**Tab: Python + Flask**

```python
import requests

def uploadToDefectDojo(filename, is_new_import):
    multipart_form_data = {
        'file': (filename, open(filename, 'rb')),
        'scan_type': (None, 'StackHawk HawkScan'),
        'product_name': (None, '<YOUR_DEFECT_DOJO_PRODUCT_NAME>'),
        'engagement_name': (None, '<YOUR_DEFECT_DOJO_ENGAGEMENT_NAME>'),

        # optional, used for `import-scan`
        'product_type_name': (None, '<YOUR_DEFECT_DOJO_PRODUCT_TYPE_NAME>'),

        # optional, used for `reimport-scan`
        'test_title': (None, '<YOUR_DEFECT_DOJO_TEST_TITLE>'),

        # Example available form options can be found @
        # https://demo.defectdojo.org/api/v2/oa3/swagger-ui/
    }

    uri = '/api/v2/import-scan/' if is_new_import else '/api/v2/reimport-scan/'
    response = requests.post(
        defect_dojo_domain + uri,
        files=multipart_form_data,
        headers={
            'Authorization': 'Token <YOUR_DEFECT_DOJO_API_KEY>',
        }
    )
    print(response.content)
```

## Feedback

Have any suggestions, feature requests, or feedback to share? [Contact StackHawk Support](https://docs.stackhawk.com/support/).
