Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added labs/assets/curl_api_products.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/assets/docker_run_juice_shop.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/assets/page_load.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions labs/lab10/imports/import-grype-vuln-results.json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"minimum_severity":"Info","active":false,"verified":false,"endpoint_to_add":null,"product_type_name":"Engineering","product_name":"Juice Shop","engagement_name":"Labs Security Testing","auto_create_context":true,"deduplication_on_engagement":false,"lead":null,"push_to_jira":false,"api_scan_configuration":null,"create_finding_groups_for_all_findings":true,"test_id":10,"engagement_id":2,"product_id":2,"product_type_id":2,"statistics":{"after":{"info":{"active":12,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":12},"low":{"active":3,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":3},"medium":{"active":32,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":32},"high":{"active":64,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":64},"critical":{"active":11,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":11},"total":{"active":122,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":122}}},"apply_tags_to_findings":false,"apply_tags_to_endpoints":false,"scan_type":"Anchore Grype","close_old_findings":false,"close_old_findings_product_scope":false,"test":10}
1 change: 1 addition & 0 deletions labs/lab10/imports/import-nuclei-results.json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"minimum_severity":"Info","active":false,"verified":false,"endpoint_to_add":null,"product_type_name":"Engineering","product_name":"Juice Shop","engagement_name":"Labs Security Testing","auto_create_context":true,"deduplication_on_engagement":false,"lead":null,"push_to_jira":false,"api_scan_configuration":null,"create_finding_groups_for_all_findings":true,"test_id":9,"engagement_id":2,"product_id":2,"product_type_id":2,"statistics":{"after":{"info":{"active":23,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":23},"low":{"active":1,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":1},"medium":{"active":1,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":1},"high":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"critical":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"total":{"active":25,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":25}}},"apply_tags_to_findings":false,"apply_tags_to_endpoints":false,"scan_type":"Nuclei Scan","close_old_findings":false,"close_old_findings_product_scope":false,"test":9}
1 change: 1 addition & 0 deletions labs/lab10/imports/import-semgrep-results.json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"minimum_severity":"Info","active":false,"verified":false,"endpoint_to_add":null,"product_type_name":"Engineering","product_name":"Juice Shop","engagement_name":"Labs Security Testing","auto_create_context":true,"deduplication_on_engagement":false,"lead":null,"push_to_jira":false,"api_scan_configuration":null,"create_finding_groups_for_all_findings":true,"test_id":7,"engagement_id":2,"product_id":2,"product_type_id":2,"statistics":{"after":{"info":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"low":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"medium":{"active":18,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":18},"high":{"active":7,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":7},"critical":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"total":{"active":25,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":25}}},"pro":["Did you know, Pro has an automated no-code connector for Semgrep JSON Report? Try today for free or email us at hello@defectdojo.com"],"apply_tags_to_findings":false,"apply_tags_to_endpoints":false,"scan_type":"Semgrep JSON Report","close_old_findings":false,"close_old_findings_product_scope":false,"test":7}
1 change: 1 addition & 0 deletions labs/lab10/imports/import-trivy-vuln-detailed.json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"minimum_severity":"Info","active":false,"verified":false,"endpoint_to_add":null,"product_type_name":"Engineering","product_name":"Juice Shop","engagement_name":"Labs Security Testing","auto_create_context":true,"deduplication_on_engagement":false,"lead":null,"push_to_jira":false,"api_scan_configuration":null,"create_finding_groups_for_all_findings":true,"test_id":8,"engagement_id":2,"product_id":2,"product_type_id":2,"statistics":{"after":{"info":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"low":{"active":18,"verified":18,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":18},"medium":{"active":36,"verified":34,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":36},"high":{"active":83,"verified":81,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":83},"critical":{"active":10,"verified":10,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":10},"total":{"active":147,"verified":143,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":147}}},"apply_tags_to_findings":false,"apply_tags_to_endpoints":false,"scan_type":"Trivy Scan","close_old_findings":false,"close_old_findings_product_scope":false,"test":8}
1 change: 1 addition & 0 deletions labs/lab10/imports/import-zap-report-noauth.xml.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"minimum_severity":"Info","active":false,"verified":false,"endpoint_to_add":null,"product_type_name":"Engineering","product_name":"Juice Shop","engagement_name":"Labs Security Testing","auto_create_context":true,"deduplication_on_engagement":false,"lead":null,"push_to_jira":false,"api_scan_configuration":null,"create_finding_groups_for_all_findings":true,"test_id":11,"engagement_id":2,"product_id":2,"product_type_id":2,"statistics":{"after":{"info":{"active":4,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":4},"low":{"active":6,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":6},"medium":{"active":2,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":2},"high":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"critical":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"total":{"active":12,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":12}}},"apply_tags_to_findings":false,"apply_tags_to_endpoints":false,"scan_type":"ZAP Scan","close_old_findings":false,"close_old_findings_product_scope":false,"test":11}
82 changes: 78 additions & 4 deletions labs/lab10/imports/run-imports.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ SCAN_NUCLEI="${SCAN_NUCLEI:-}"

if $have_jq; then
echo "Discovering importer names from /test_types/ ..."
mapfile -t types < <(curl -sS -H "Authorization: Token $DD_TOKEN" "$DD_API/test_types/?limit=2000" | jq -r '.results[].name')
types=()
while IFS= read -r line; do
types+=("$line")
done < <(curl -sS -H "Authorization: Token $DD_TOKEN" "$DD_API/test_types/?limit=2000" | jq -r '.results[].name')
choose_type() {
local pat="$1"
local fallback="$2"
Expand All @@ -63,9 +66,9 @@ if $have_jq; then
if [[ -z "$val" ]]; then val="$fallback"; fi
echo "$val"
}
SCAN_ZAP="${SCAN_ZAP:-$(choose_type '^ZAP' 'ZAP Scan')}"
SCAN_SEMGREP="${SCAN_SEMGREP:-$(choose_type '^Semgrep' 'Semgrep JSON Report')}"
SCAN_TRIVY="${SCAN_TRIVY:-$(choose_type '^Trivy' 'Trivy Scan')}"
SCAN_ZAP="${SCAN_ZAP:-$(choose_type '^ZAP Scan$' 'ZAP Scan')}"
SCAN_SEMGREP="${SCAN_SEMGREP:-$(choose_type '^Semgrep JSON Report$' 'Semgrep JSON Report')}"
SCAN_TRIVY="${SCAN_TRIVY:-$(choose_type '^Trivy Scan$' 'Trivy Scan')}"
SCAN_NUCLEI="${SCAN_NUCLEI:-$(choose_type '^Nuclei' 'Nuclei Scan')}"
# Grype importer (commonly named "Anchore Grype")
if [[ -z "${SCAN_GRYPE:-}" ]]; then
Expand Down Expand Up @@ -114,6 +117,70 @@ import_scan() {
| tee "$out"
}

convert_zap_json_to_xml() {
local src="$1"
local dest="$2"
python3 - "$src" "$dest" <<'PY'
import json
import sys
import xml.etree.ElementTree as ET

src, dest = sys.argv[1], sys.argv[2]
with open(src, encoding="utf-8") as handle:
data = json.load(handle)


def build(parent, key, value):
if isinstance(value, list):
if key == "alerts":
alerts_node = ET.SubElement(parent, "alerts")
for item in value:
child = ET.SubElement(alerts_node, "alertitem")
for sub_key, sub_value in item.items():
build(child, sub_key, sub_value)
return
if key == "instances":
instances_node = ET.SubElement(parent, "instances")
for item in value:
child = ET.SubElement(instances_node, "instance")
for sub_key, sub_value in item.items():
build(child, sub_key, sub_value)
return
child_tag = key
if key.endswith("ies"):
child_tag = key[:-3] + "y"
elif key.endswith("s") and key not in {"alerts"}:
child_tag = key[:-1]
for item in value:
child = ET.SubElement(parent, child_tag)
if isinstance(item, dict):
for sub_key, sub_value in item.items():
build(child, sub_key, sub_value)
elif isinstance(item, list):
build(child, child_tag, item)
elif item is not None:
child.text = str(item)
return

if key.startswith("@"):
parent.set(key[1:], "" if value is None else str(value))
return

child = ET.SubElement(parent, key)
if isinstance(value, dict):
for sub_key, sub_value in value.items():
build(child, sub_key, sub_value)
elif value is not None:
child.text = str(value)


root = ET.Element("OWASPZAPReport")
for key, value in data.items():
build(root, key, value)
ET.ElementTree(root).write(dest, encoding="utf-8", xml_declaration=True)
PY
}

# Candidate paths per tool
zap_file="labs/lab5/zap/zap-report-noauth.json"
semgrep_file="labs/lab5/semgrep/semgrep-results.json"
Expand All @@ -123,6 +190,13 @@ nuclei_file="labs/lab5/nuclei/nuclei-results.json"
# Grype
grype_file="labs/lab4/syft/grype-vuln-results.json"

if [[ "$zap_file" == *.json ]]; then
zap_xml="$out_dir/zap-report-noauth.xml"
echo "Converting ZAP JSON report to XML: $zap_xml"
convert_zap_json_to_xml "$zap_file" "$zap_xml"
zap_file="$zap_xml"
fi

import_scan "$SCAN_ZAP" "$zap_file"
import_scan "$SCAN_SEMGREP" "$semgrep_file"
import_scan "$SCAN_TRIVY" "$trivy_file"
Expand Down
2 changes: 2 additions & 0 deletions labs/lab10/imports/zap-report-noauth.xml

Large diffs are not rendered by default.

184 changes: 184 additions & 0 deletions labs/lab10/report/dojo-report.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>DefectDojo Stakeholder Report</title>
<style>
:root {
--bg: #f6f3eb;
--panel: #fffdf8;
--ink: #202020;
--muted: #6b6559;
--accent: #9d3c1f;
--border: #d8cfbf;
}
body {
margin: 0;
font-family: Georgia, "Times New Roman", serif;
color: var(--ink);
background:
radial-gradient(circle at top right, #f2d7c2 0, rgba(242, 215, 194, 0) 35%),
linear-gradient(180deg, #f8f5ee 0%, var(--bg) 100%);
}
main {
max-width: 1080px;
margin: 0 auto;
padding: 40px 24px 64px;
}
h1, h2 {
margin: 0 0 12px;
line-height: 1.1;
}
p, li {
font-size: 16px;
line-height: 1.6;
}
.hero, .panel {
background: var(--panel);
border: 1px solid var(--border);
border-radius: 18px;
padding: 24px;
box-shadow: 0 20px 40px rgba(71, 46, 24, 0.08);
}
.hero {
margin-bottom: 24px;
}
.eyebrow {
color: var(--accent);
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 12px;
font-weight: bold;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
margin-top: 24px;
}
.stat {
font-size: 34px;
font-weight: bold;
color: var(--accent);
margin-top: 8px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 12px;
font-size: 15px;
}
th, td {
padding: 10px 12px;
border-bottom: 1px solid var(--border);
text-align: left;
vertical-align: top;
}
th {
color: var(--muted);
font-weight: 600;
}
.section {
margin-top: 24px;
}
</style>
</head>
<body>
<main>
<section class="hero">
<div class="eyebrow">Lab 10 Report</div>
<h1>DefectDojo Stakeholder Summary</h1>
<p>
Engagement: <strong>Labs Security Testing</strong><br>
Date captured: <strong>2026-04-13</strong>
</p>
<p>
This report consolidates imported findings from ZAP, Semgrep, Trivy, Nuclei, and Grype
into a single view for triage, communication, and basic governance tracking.
</p>
</section>

<section class="grid">
<div class="panel">
<div class="eyebrow">Open Findings</div>
<div class="stat">331</div>
<p>Active findings currently requiring remediation or disposition.</p>
</div>
<div class="panel">
<div class="eyebrow">Verified</div>
<div class="stat">143</div>
<p>Findings confirmed by imported evidence or platform state.</p>
</div>
<div class="panel">
<div class="eyebrow">Mitigated</div>
<div class="stat">0</div>
<p>Findings already closed or mitigated in the current dataset.</p>
</div>
</section>

<section class="grid section">
<div class="panel">
<h2>Severity Mix</h2>
<table>
<thead><tr><th>Severity</th><th>Open</th><th>Closed</th></tr></thead>
<tbody><tr><td>Critical</td><td>21</td><td>0</td></tr>
<tr><td>High</td><td>154</td><td>0</td></tr>
<tr><td>Medium</td><td>89</td><td>0</td></tr>
<tr><td>Low</td><td>28</td><td>0</td></tr>
<tr><td>Info</td><td>39</td><td>0</td></tr></tbody>
</table>
</div>
<div class="panel">
<h2>Findings Per Tool</h2>
<table>
<thead><tr><th>Tool</th><th>Findings</th></tr></thead>
<tbody><tr><td>Grype</td><td>122</td></tr>
<tr><td>Nuclei</td><td>25</td></tr>
<tr><td>Semgrep</td><td>25</td></tr>
<tr><td>Trivy</td><td>147</td></tr>
<tr><td>ZAP</td><td>12</td></tr></tbody>
</table>
</div>
</section>

<section class="grid section">
<div class="panel">
<h2>SLA Outlook</h2>
<p>0 overdue findings and 21 more due within 14 days.</p>
</div>
<div class="panel">
<h2>Recurring CWE Categories</h2>
<ul><li>CWE-1333: 29</li>
<li>CWE-407: 13</li>
<li>CWE-79: 11</li>
<li>CWE-22: 11</li>
<li>CWE-200: 9</li></ul>
</div>
</section>

<section class="panel section">
<h2>Highest-Priority Findings</h2>
<table>
<thead>
<tr><th>ID</th><th>Severity</th><th>Tool</th><th>CWE</th><th>Status</th><th>Title</th></tr>
</thead>
<tbody><tr><td>188</td><td>Critical</td><td>Trivy</td><td>787</td><td>Active, Verified</td><td>CVE-2025-15467 Libssl3 3.0.17-1~deb12u2</td></tr>
<tr><td>204</td><td>Critical</td><td>Trivy</td><td>328</td><td>Active, Verified</td><td>CVE-2023-46233 Crypto-Js 3.3.0</td></tr>
<tr><td>214</td><td>Critical</td><td>Trivy</td><td>20</td><td>Active, Verified</td><td>CVE-2015-9235 Jsonwebtoken 0.1.0</td></tr>
<tr><td>219</td><td>Critical</td><td>Trivy</td><td>20</td><td>Active, Verified</td><td>CVE-2015-9235 Jsonwebtoken 0.4.0</td></tr>
<tr><td>226</td><td>Critical</td><td>Trivy</td><td>1321</td><td>Active, Verified</td><td>CVE-2019-10744 Lodash 2.4.2</td></tr>
<tr><td>232</td><td>Critical</td><td>Trivy</td><td></td><td>Active, Verified</td><td>GHSA-5mrr-rgp6-x4gr Marsdb 0.6.11</td></tr>
<tr><td>310</td><td>Critical</td><td>Trivy</td><td>74</td><td>Active, Verified</td><td>CVE-2023-32314 Vm2 3.9.17</td></tr>
<tr><td>311</td><td>Critical</td><td>Trivy</td><td>94</td><td>Active, Verified</td><td>CVE-2023-37466 Vm2 3.9.17</td></tr>
<tr><td>312</td><td>Critical</td><td>Trivy</td><td>78</td><td>Active, Verified</td><td>CVE-2023-37903 Vm2 3.9.17</td></tr>
<tr><td>313</td><td>Critical</td><td>Trivy</td><td>94</td><td>Active, Verified</td><td>CVE-2026-22709 Vm2 3.9.17</td></tr>
<tr><td>346</td><td>Critical</td><td>Grype</td><td></td><td>Active</td><td>GHSA-whpj-8f3w-67p5 in vm2:3.9.17</td></tr>
<tr><td>347</td><td>Critical</td><td>Grype</td><td></td><td>Active</td><td>GHSA-g644-9gfx-q4q4 in vm2:3.9.17</td></tr>
<tr><td>348</td><td>Critical</td><td>Grype</td><td></td><td>Active</td><td>GHSA-c7hr-j4mj-j2w6 in jsonwebtoken:0.1.0</td></tr>
<tr><td>349</td><td>Critical</td><td>Grype</td><td></td><td>Active</td><td>GHSA-c7hr-j4mj-j2w6 in jsonwebtoken:0.4.0</td></tr>
<tr><td>350</td><td>Critical</td><td>Grype</td><td></td><td>Active</td><td>GHSA-cchq-frgv-rjh5 in vm2:3.9.17</td></tr></tbody>
</table>
</section>
</main>
</body>
</html>
Loading