π¨βπ§ Vulnerability Management and Remediation
Reports from different tools may be very hard to be orchestrated, and here is where Management tools like DefectDojo come in handy.
SAST Export Results
Most SAST tools allow to export the results as reports. For this example, we added output attributes aswell as artifact funtionality to upload these results to the pipeline build.
# Scan for Git Leaked credentials
gitleaks:
stage: test
image:
name: zricethezav/gitleaks:latest
entrypoint: [""]
script:
- gitleaks detect --verbose --source . -f json -r gitleaks.json #(1)
allow_failure: true
artifacts:
when: always
paths:
- gitleaks.json #(2)
# Scan for NodeJS SAST vulnerabilies
njsscan:
stage: test
image: python
before_script:
- pip3 install --upgrade njsscan
script:
- njsscan --exit-warning . --sarif -o njsscan.sarif #(3)
allow_failure: true
artifacts:
when: always
paths:
- njsscan.sarif #(4)
# Scan with SemGrep
semgrep:
stage: test
image: semgrep/semgrep
variables:
SEMGREP_RULES: p/javascript
script:
- semgrep ci --json --output semgrep.json #(5)
allow_failure: true
artifacts:
when: always
paths:
- semgrep.json #(6)
-f json -r gitleaks.jsonexports the file asjsonand asgitleaks.json.- This artifact block will upload the
gitleaks.jsonfile on the current build always (even if task fails). --sarif -o njsscan.sarifexports the file assarifand asnjsscan.sarif.- This artifact block will upload the
njsscan.sariffile on the current build always (even if task fails). --json --output semgrep.jsonexports the file asjsonand assemgrep.json.- This artifact block will upload the
semgrep.jsonfile on the current build always (even if task fails).
DefectDojo
We will use this tool to deploy it locally in order to understand how it works. Nana on the course used the Demo site, however, I wanted to try the Docker-compose version.
- Deploy DefectDojo locally.
# π¨βπ§ Vulnerability Management and Remediation
Reports from different tools may be very hard to be orchestrated, and here is where Management tools like [DefectDojo](https://defectdojo.com/) come in handy.
## SAST Export Results
Most SAST tools allow to export the results as reports. For this example, we added output attributes aswell as artifact funtionality to upload these results to the pipeline build.
```yaml
# Scan for Git Leaked credentials
gitleaks:
stage: test
image:
name: zricethezav/gitleaks:latest
entrypoint: [""]
script:
- gitleaks detect --verbose --source . -f json -r gitleaks.json #(1)
allow_failure: true
artifacts:
when: always
paths:
- gitleaks.json #(2)
# Scan for NodeJS SAST vulnerabilies
njsscan:
stage: test
image: python
before_script:
- pip3 install --upgrade njsscan
script:
- njsscan --exit-warning . --sarif -o njsscan.sarif #(3)
allow_failure: true
artifacts:
when: always
paths:
- njsscan.sarif #(4)
# Scan with SemGrep
semgrep:
stage: test
image: semgrep/semgrep
variables:
SEMGREP_RULES: p/javascript
script:
- semgrep ci --json --output semgrep.json #(5)
allow_failure: true
artifacts:
when: always
paths:
- semgrep.json #(6)
-f json -r gitleaks.jsonexports the file asjsonand asgitleaks.json.- This artifact block will upload the
gitleaks.jsonfile on the current build always (even if task fails). --sarif -o njsscan.sarifexports the file assarifand asnjsscan.sarif.- This artifact block will upload the
njsscan.sariffile on the current build always (even if task fails). --json --output semgrep.jsonexports the file asjsonand assemgrep.json.- This artifact block will upload the
semgrep.jsonfile on the current build always (even if task fails).
DefectDojo
We will use this tool to deploy it locally in order to understand how it works. Nana on the course used the Demo site, however, I wanted to try the Docker-compose version instead of the ephimeral DefectDojo Demo site.
- Deploy DefectDojo locally.
# Clone the project
git clone https://github.com/DefectDojo/django-DefectDojo
cd django-DefectDojo
# Check if your installed toolkit is compatible
./docker/docker-compose-check.sh
# Building Docker images
docker compose build
# Run the application (for other profiles besides postgres-redis see
# https://github.com/DefectDojo/django-DefectDojo/blob/dev/readme-docs/DOCKER.md)
docker compose up -d
# Obtain admin credentials. The initializer can take up to 3 minutes to run.
# Use docker compose logs -f initializer to track its progress.
docker compose logs initializer | grep "Admin password:"
Upload Reports to DefectDojo
We will upload reports automatically to DefectDojo form the pipeline.
- Head to DefectDojo page and get the API Key:
DefectDojo page > User Profile > API v2 Keyand copy the key. For example7e494885053ffdeb621d02909201581581872bc4.
import requests
import sys
import os
api_key = os.environ["DEFECTDOJO_API_KEY"]
file_name = sys.argv[1]
scan_type = ''
if file_name == 'gitleaks.json':
scan_type = 'Gitleaks Scan'
elif file_name == 'njsscan.sarif':
scan_type = 'SARIF'
elif file_name == 'semgrep.json':
scan_type = 'Semgrep JSON Report'
elif file_name == 'retire.json':
scan_type = 'Retire.js Scan'
headers = {
'Authorization': f'Token {api_key}'
}
url = 'http://95.17.91.21:8080/api/v2/import-scan/'
data = {
'auto_create_context': True,
'active': True, # it will mark the findings as active
'verified': True, # mark as findings as verified automatically
'scan_type': scan_type, # this is the type of scan we specified earlyer manually
'minimum_severity': 'Low', # results with "info" severity won't be imported
'product_name': 'Juice Shop',
'engagement': 5
}
files = {
'file': open(file_name, 'rb')
}
response = requests.post(url, headers=headers, data=data, files=files)
if response.status_code == 201:
print('Scan results imported successfully')
else:
print(f'Failed to import scan results: Status_Code: { response.status_code} - Response: {response.content}')
However, this is how the complete CICD pipeline looks like. I also added the "DEFECTDOJO_API_KEY" as a variable to the code, to avoid hardcoding any secret value.
variables:
IMAGE_NAME: onisimiacob/demo-app
IMAGE_VERSION: juice-shop-1.0
stages:
- cache
- test
- build
# Improove build times with a cache task that saves the dependencies as an artifact
create_cache:
image: node:18-bullseye
stage: cache
script:
- yarn install --ignore-engines
cache:
key:
files:
- yarn.lock
paths:
- node_modules
- yarn.lock
- .yarn
policy: pull-push
# Test using the cache to speedup testing
yarn_test:
image: node:18-bullseye
stage: test
script:
- yarn install --ignore-engines # fix The engine "node" is incompatible with this module. Expected version "20 || >=22". Got "18.20.8"
- yarn test
cache:
key:
files:
- yarn.lock
paths:
- node_modules
- yarn.lock
- .yarn
policy: pull
# Scan for Git Leaked credentials
gitleaks:
stage: test
image:
name: zricethezav/gitleaks:latest
entrypoint: [""]
script:
- gitleaks detect --verbose --source . -f json -r gitleaks.json
allow_failure: true
artifacts:
when: always
paths:
- gitleaks.json
# Scan for NodeJS SAST vulnerabilies
njsscan:
stage: test
image: python
before_script:
- pip3 install --upgrade njsscan
script:
- njsscan --exit-warning . --sarif -o njsscan.sarif
allow_failure: true
artifacts:
when: always
paths:
- njsscan.sarif
# Scan with SemGrep
semgrep:
stage: test
image: semgrep/semgrep
variables:
SEMGREP_RULES: p/javascript
script:
- semgrep ci --json --output semgrep.json
allow_failure: true
artifacts:
when: always
paths:
- semgrep.json
# Upload results to DefectDojo
upload_reports:
stage: test
image: python
needs: ["gitleaks", "njsscan", "semgrep"]
when: always
variables:
DEFECTDOJO_API_KEY: $DEFECTDOJO_API_KEY
before_script:
- pip3 install requests
script:
- python3 upload-reports.py gitleaks.json
- python3 upload-reports.py njsscan.sarif
- python3 upload-reports.py semgrep.json
# Build the docker image
build_image:
stage: build
image: docker:24
services:
- docker:24-dind
variables:
DOCKER_USER: $DOCKER_USER
DOCKER_PASS: $DOCKER_PASS
before_script:
- echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
script:
- docker build -t $IMAGE_NAME:$IMAGE_VERSION .
- docker push $IMAGE_NAME:$IMAGE_VERSION
This is how DefectDojo looks after pipeline gets executed and scans got imported.

