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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ In addition, there is one compromised package, that lacks a CVE, but is maliciou
| CVE-2019-10744 | lodash | [https://nvd.nist.gov/vuln/detail/CVE-2019-10744](https://nvd.nist.gov/vuln/detail/CVE-2019-10744)|
| CVE-2019-8331 | pug | [https://nvd.nist.gov/vuln/detail/CVE-2019-8331](https://nvd.nist.gov/vuln/detail/CVE-2019-8331)|
| CVE-2020-8116 | dot-prop | [https://nvd.nist.gov/vuln/detail/CVE-2020-8116](https://nvd.nist.gov/vuln/detail/CVE-2020-8116)|
| CVE-2020-7789 | node-notifier | [https://nvd.nist.gov/vuln/detail/CVE-2020-7789](https://nvd.nist.gov/vuln/detail/CVE-2020-7789)|
| CVE-2024-21534 | jsonpath-plus | [https://nvd.nist.gov/vuln/detail/CVE-2024-21534](https://nvd.nist.gov/vuln/detail/CVE-2024-21534)|
| CVE-2021-44906 | minimist | [https://nvd.nist.gov/vuln/detail/CVE-2021-44906](https://nvd.nist.gov/vuln/detail/CVE-2021-44906)|

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README lists serialize-javascript under CVE-2020-7660 only, but the app UI/startup log references CVE-2019-16769 as well. Please align the README entry with the rest of the app (either list both CVEs everywhere or consistently pick one) to avoid confusing users about which vulnerability is being demonstrated.

Suggested change
| CVE-2021-44906 | minimist | [https://nvd.nist.gov/vuln/detail/CVE-2021-44906](https://nvd.nist.gov/vuln/detail/CVE-2021-44906)|
| CVE-2021-44906 | minimist | [https://nvd.nist.gov/vuln/detail/CVE-2021-44906](https://nvd.nist.gov/vuln/detail/CVE-2021-44906)|
| CVE-2019-16769 | serialize-javascript | [https://nvd.nist.gov/vuln/detail/CVE-2019-16769](https://nvd.nist.gov/vuln/detail/CVE-2019-16769)|

Copilot uses AI. Check for mistakes.
| CVE-2020-7660 | serialize-javascript | [https://nvd.nist.gov/vuln/detail/CVE-2020-7660](https://nvd.nist.gov/vuln/detail/CVE-2020-7660)|
| Malicious Package (No CVE) | xz-java | [https://central.sonatype.com/artifact/io.github.xz-java/xz-java](https://central.sonatype.com/artifact/io.github.xz-java/xz-java)|


Expand Down Expand Up @@ -113,6 +117,10 @@ SCAGoat features an interactive vulnerability dashboard that allows users to exp
- **Log4j (CVE-2021-44228)**: Log4Shell vulnerability demonstration
- **Pug (CVE-2019-8331)**: Denial of Service vulnerability in the template engine
- **Dot-Prop (CVE-2020-8116)**: Prototype pollution vulnerability allowing property manipulation
- **Node-Notifier (CVE-2020-7789)**: OS command injection on Linux via unsanitized options
- **JSONPath-Plus (CVE-2024-21534)**: Critical RCE via unsafe vm usage (CVSS 9.8)
- **Minimist (CVE-2021-44906)**: Prototype pollution in argument parser
- **Serialize-JavaScript (CVE-2020-7660)**: XSS via arbitrary code injection

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bullet lists Serialize-JavaScript as CVE-2020-7660, while other parts of the app (e.g., startup log / dashboard card) mention CVE-2019-16769 too. Please make the CVE reference consistent across README and UI.

Suggested change
- **Serialize-JavaScript (CVE-2020-7660)**: XSS via arbitrary code injection
- **Serialize-JavaScript (CVE-2020-7660, CVE-2019-16769)**: XSS via arbitrary code injection

Copilot uses AI. Check for mistakes.

Each vulnerability includes an interactive demo to help security professionals, developers, and students understand how these vulnerabilities work and how they can be exploited.

Expand Down
68 changes: 68 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ console.log('- Malicious Package: XZ-Java backend demo');
console.log('- CVE-2020-9547: jackson-databind backend demo');
console.log('- CVE-2019-8331: pug v2.0.4 (Denial of Service vulnerability)');
console.log('- CVE-2020-8116: dot-prop v4.2.0 (Prototype pollution vulnerability)');
console.log('- CVE-2020-7789: node-notifier v5.4.4 (Command injection vulnerability)');
console.log('- CVE-2024-21534: jsonpath-plus v7.0.0 (RCE vulnerability)');
console.log('- CVE-2021-44906: minimist v1.2.0 (Prototype pollution vulnerability)');
console.log('- CVE-2019-16769: serialize-javascript v2.1.1 (XSS vulnerability)');

// Basic routes
app.get('/', function (req, res) {
Expand Down Expand Up @@ -763,6 +767,22 @@ app.get('/dotprop', function (req, res) {
res.sendFile(__dirname + '/templates/dotprop.html');
});

app.get('/serialize', function (req, res) {
res.sendFile(__dirname + '/templates/serialize.html');
});

app.get('/nodenotifier', function (req, res) {
res.sendFile(__dirname + '/templates/nodenotifier.html');
});

app.get('/jsonpath', function (req, res) {
res.sendFile(__dirname + '/templates/jsonpath.html');
});

app.get('/minimist', function (req, res) {
res.sendFile(__dirname + '/templates/minimist.html');
});

// Add the API endpoint for rendering Pug templates
app.post('/api/render-pug', function (req, res) {
const template = req.body.template;
Expand Down Expand Up @@ -889,6 +909,54 @@ app.post('/api/dotprop', function (req, res) {
}
});

// CVE-2020-7789: node-notifier command injection
app.post('/api/notify', function (req, res) {
const { appName, title, message } = req.body || {};
const notifier = require('node-notifier');
try {
Comment on lines +915 to +916

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In /api/notify, require('node-notifier') is executed outside the try block. If the module fails to load (install/platform issues), the handler won't return the intended JSON error response and will fall back to Express's default error handling. Move the require inside the try (or wrap it in its own try/catch) and respond with a structured JSON error when loading fails.

Suggested change
const notifier = require('node-notifier');
try {
try {
const notifier = require('node-notifier');

Copilot uses AI. Check for mistakes.
// Vulnerable: appName passed as array - on Linux with notify-send, unsanitized input can lead to command injection
notifier.notify({
title: title || 'Notification',
message: message || 'Demo',
appName: appName ? [String(appName)] : undefined
}, function (err) {
if (err) {
res.json({ error: err.message, warning: 'Vulnerable node-notifier v5.4.4 (CVE-2020-7789) - command injection possible on Linux' });
} else {
res.json({ success: true, warning: 'CVE-2020-7789: Unsanitized options passed to shell' });
}
});
} catch (err) {
res.json({ error: err.message });
}
});

// CVE-2024-21534: jsonpath-plus RCE via unsafe vm usage
app.post('/api/jsonpath', function (req, res) {
const { path: jsonPath, data } = req.body || {};
try {
const { JSONPath } = require('jsonpath-plus');
const parsed = typeof data === 'string' ? JSON.parse(data) : data;
// Vulnerable: jsonpath-plus < 10.2.0 uses vm unsafely with user input
const result = JSONPath({ path: jsonPath || '$.', json: parsed });
res.json({ result });
} catch (err) {
res.json({ error: err.message });
}
});

// CVE-2021-44906: minimist prototype pollution (used via dependency or direct)
app.post('/api/minimist', function (req, res) {
const args = req.body.args || [];
try {
const parse = require('minimist');
const result = parse(args);
res.json({ result });
Comment on lines +948 to +954

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parsing attacker-controlled args with vulnerable minimist can prototype-pollute the running Node process (e.g., __proto__ payloads) and permanently affect subsequent requests across the whole app. To keep the demo reliable, consider isolating the parse in a child process / worker (or explicitly cleaning up any polluted keys after the request) and/or return evidence of pollution in the response for clarity.

Copilot uses AI. Check for mistakes.
} catch (err) {
res.json({ error: err.message });
}
});

app.listen(3000, function () {
const asciiArt = `
................................................,,::;;;++*******+++;;::,,...............................................
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
"pug": "^2.0.4",
"serialize-javascript": "2.1.1",
"trim-newlines": "4.0.0",
"node-notifier": "5.4.4",
"jsonpath-plus": "7.0.0",
"minimist": "1.2.0",
"ws": "6.2.1"
Comment on lines +29 to 30

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

package.json was updated with new dependencies, but package-lock.json is not updated in this PR. If the project relies on npm ci / lockfile installs, this will cause inconsistent installs or CI failures. Regenerate and commit an updated lockfile (or document/remove lockfile usage).

Suggested change
"minimist": "1.2.0",
"ws": "6.2.1"
"minimist": "1.2.0"

Copilot uses AI. Check for mistakes.
},
"devDependencies": {
Expand Down
50 changes: 49 additions & 1 deletion templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<a href="/pug"><i class="fas fa-file-code fa-fw"></i> Pug (CVE-2019-8331)</a>
<a href="/lodash"><i class="fas fa-code fa-fw"></i> Lodash (CVE-2019-10744)</a>
<a href="/dotprop"><i class="fas fa-dot-circle fa-fw"></i> Dot-Prop (CVE-2020-8116)</a>
<a href="/serialize"><i class="fas fa-exchange-alt fa-fw"></i> Serialize-JS (CVE-2020-7660)</a>
</div>
</div>

Expand All @@ -74,7 +75,9 @@
</div>
<div class="dropdown-content">
<a href="/trimnewlines"><i class="fas fa-cut fa-fw"></i> Trim-Newlines (CVE-2021-33623)</a>

<a href="/nodenotifier"><i class="fas fa-bell fa-fw"></i> Node-Notifier (CVE-2020-7789)</a>
<a href="/jsonpath"><i class="fas fa-code fa-fw"></i> JSONPath-Plus (CVE-2024-21534)</a>
<a href="/minimist"><i class="fas fa-sliders-h fa-fw"></i> Minimist (CVE-2021-44906)</a>
<a href="/checkip"><i class="fas fa-search fa-fw"></i> Checkip (SSRF)</a>
</div>
</div>
Expand Down Expand Up @@ -276,6 +279,51 @@ <h3>CVE-2020-8116</h3>
</div>
</div>
</div>
<div class="grid-item" onclick="window.location.href='/serialize'">
<div class="vuln-card">
<div class="vuln-header">
<i class="fas fa-exchange-alt vuln-icon"></i>
<span class="vuln-type">Serialize-JavaScript</span>
</div>
<div class="vuln-body">
<h3>CVE-2019-16769 / CVE-2020-7660</h3>
<p>XSS via arbitrary code injection in serialize-javascript</p>
</div>
<div class="vuln-footer">
<a href="https://nvd.nist.gov/vuln/detail/CVE-2020-7660" target="_blank" class="vuln-link">Learn More</a>
</div>
</div>
</div>
<div class="grid-item" onclick="window.location.href='/jsonpath'">
<div class="vuln-card">
<div class="vuln-header">
<i class="fas fa-code vuln-icon"></i>
<span class="vuln-type">JSONPath-Plus</span>
</div>
<div class="vuln-body">
<h3>CVE-2024-21534</h3>
<p>Critical RCE via unsafe vm usage (CVSS 9.8)</p>
</div>
<div class="vuln-footer">
<a href="https://nvd.nist.gov/vuln/detail/CVE-2024-21534" target="_blank" class="vuln-link">Learn More</a>
</div>
</div>
</div>
<div class="grid-item" onclick="window.location.href='/minimist'">
<div class="vuln-card">
<div class="vuln-header">
<i class="fas fa-sliders-h vuln-icon"></i>
<span class="vuln-type">Minimist</span>
</div>
<div class="vuln-body">
<h3>CVE-2021-44906</h3>
<p>Prototype pollution in argument parser</p>
</div>
<div class="vuln-footer">
<a href="https://nvd.nist.gov/vuln/detail/CVE-2021-44906" target="_blank" class="vuln-link">Learn More</a>
</div>
</div>
</div>
</div>
</div>

Expand Down
91 changes: 91 additions & 0 deletions templates/jsonpath.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSONPath-Plus RCE - SCAGoat</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link href="../static/css/style.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
</head>
<body>
<div id="particles-js"></div>

<nav class="navbar">
<a href="/"><i class="fas fa-home"></i> Home</a>
<a href="/markdown"><i class="fas fa-file-alt"></i> Markdown</a>
<a href="/checkip"><i class="fas fa-search"></i> Checkip</a>
<a href="/trimnewlines"><i class="fas fa-cut"></i> Trim-Newlines</a>
<a href="/jsonpath" class="active"><i class="fas fa-code"></i> JSONPath-Plus</a>
<a href="/chat-ui"><i class="fas fa-comment"></i> Chat</a>
<a href="http://localhost:8080" target="_blank"><i class="fas fa-server"></i> Backend</a>
</nav>

<div class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold text-white text-center mb-8">JSONPath-Plus Remote Code Execution</h1>

<div class="max-w-3xl mx-auto bg-gray-800 bg-opacity-80 p-6 rounded-lg shadow-md mb-8">
<div class="mb-6 text-white">
<h2 class="text-xl font-bold mb-2"><i class="fas fa-exclamation-triangle text-red-500 mr-2"></i>CVE-2024-21534</h2>
<p class="mb-4">jsonpath-plus versions before 10.2.0 contain a critical Remote Code Execution (RCE) vulnerability. The package uses Node's <code>vm</code> module in an unsafe manner with user-controlled input, allowing attackers to execute arbitrary JavaScript code on the server.</p>
<div class="bg-red-900 bg-opacity-70 p-3 rounded mt-4">
<p class="text-sm"><strong>CVSS Score:</strong> 9.8 (Critical)</p>
<p class="text-sm"><strong>Vulnerability Type:</strong> Remote Code Execution</p>
<p class="text-sm"><strong>Fixed Version:</strong> 10.2.0+</p>
<p class="text-sm"><strong>Current Version:</strong> 7.0.0 (Vulnerable)</p>
</div>
</div>

<div class="bg-gray-900 bg-opacity-70 p-4 rounded-lg mb-6">
<h3 class="text-lg font-bold text-white mb-3">Demonstration</h3>
<p class="text-gray-300 mb-4">Query JSON data using JSONPath. The vulnerable library processes user-supplied paths with unsafe vm usage:</p>

<form id="jsonpathForm" class="space-y-4">
<div>
<label for="jsonpath" class="block text-white text-sm font-bold mb-2">JSONPath Expression:</label>
<input type="text" id="jsonpath" class="w-full px-3 py-2 rounded-md border border-gray-600 bg-gray-700 text-white"
placeholder="e.g., $.users[*].name" value="$.users[*].name">
</div>
<div>
<label class="block text-white text-sm font-bold mb-2">Sample JSON:</label>
<textarea id="jsonData" class="w-full px-3 py-2 rounded-md border border-gray-600 bg-gray-700 text-white font-mono text-sm" rows="6">{"users": [{"name": "Alice", "id": 1}, {"name": "Bob", "id": 2}]}</textarea>
</div>
<button type="submit" class="w-full bg-red-600 hover:bg-red-700 text-white py-2 rounded-md transition">
<i class="fas fa-search mr-2"></i>Execute JSONPath Query
</button>
</form>
</div>
</div>
</div>

<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
<script>
particlesJS('particles-js', {
"particles": {"number": {"value": 80, "density": {"enable": true, "value_area": 800}}, "color": {"value": "#ffffff"},
"shape": {"type": "circle", "stroke": {"width": 0, "color": "#000000"}},
"opacity": {"value": 0.5}, "size": {"value": 3, "random": true},
"line_linked": {"enable": true, "distance": 150, "color": "#ffffff", "opacity": 0.4, "width": 1},
"move": {"enable": true, "speed": 6}, "interactivity": {"detect_on": "canvas", "events": {"onhover": {"enable": true, "mode": "grab"}, "onclick": {"enable": true, "mode": "push"}}},
"retina_detect": true
});

document.getElementById('jsonpathForm').addEventListener('submit', function(e) {
e.preventDefault();
fetch('/api/jsonpath', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
path: document.getElementById('jsonpath').value,
data: document.getElementById('jsonData').value
})
})
.then(r => r.json())
.then(data => {
if (data.error) alert('Error: ' + data.error);
else alert('Result: ' + JSON.stringify(data.result));
})
.catch(err => alert('Error: ' + err.message));
});
</script>
</body>
</html>
85 changes: 85 additions & 0 deletions templates/minimist.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minimist Prototype Pollution - SCAGoat</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link href="../static/css/style.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
</head>
<body>
<div id="particles-js"></div>

<nav class="navbar">
<a href="/"><i class="fas fa-home"></i> Home</a>
<a href="/markdown"><i class="fas fa-file-alt"></i> Markdown</a>
<a href="/checkip"><i class="fas fa-search"></i> Checkip</a>
<a href="/trimnewlines"><i class="fas fa-cut"></i> Trim-Newlines</a>
<a href="/minimist" class="active"><i class="fas fa-sliders-h"></i> Minimist</a>
<a href="/chat-ui"><i class="fas fa-comment"></i> Chat</a>
<a href="http://localhost:8080" target="_blank"><i class="fas fa-server"></i> Backend</a>
</nav>

<div class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold text-white text-center mb-8">Minimist Prototype Pollution Vulnerability</h1>

<div class="max-w-3xl mx-auto bg-gray-800 bg-opacity-80 p-6 rounded-lg shadow-md mb-8">
<div class="mb-6 text-white">
<h2 class="text-xl font-bold mb-2"><i class="fas fa-exclamation-triangle text-yellow-500 mr-2"></i>CVE-2021-44906</h2>
<p class="mb-4">minimist before 1.2.6 (and &lt;0.2.4) is vulnerable to prototype pollution. Parsing malicious argument strings can pollute the Object prototype, potentially leading to denial of service or other security impacts.</p>
<div class="bg-red-900 bg-opacity-70 p-3 rounded mt-4">
<p class="text-sm"><strong>CVSS Score:</strong> 7.3 (High)</p>
<p class="text-sm"><strong>Vulnerability Type:</strong> Prototype Pollution</p>
<p class="text-sm"><strong>Fixed Version:</strong> 1.2.6+</p>
<p class="text-sm"><strong>Current Version:</strong> 1.2.0 (Vulnerable)</p>
</div>
</div>

<div class="bg-gray-900 bg-opacity-70 p-4 rounded-lg mb-6">
<h3 class="text-lg font-bold text-white mb-3">Demonstration</h3>
<p class="text-gray-300 mb-4">Parse command-line style arguments. Try a prototype pollution payload like <code>--__proto__.polluted true</code>:</p>

<form id="minimistForm" class="space-y-4">
<div>
<label for="args" class="block text-white text-sm font-bold mb-2">Arguments (space-separated):</label>
<input type="text" id="args" class="w-full px-3 py-2 rounded-md border border-gray-600 bg-gray-700 text-white font-mono"
placeholder="e.g., --foo bar --__proto__.polluted true" value="--foo bar">
</div>
<button type="submit" class="w-full bg-red-600 hover:bg-red-700 text-white py-2 rounded-md transition">
<i class="fas fa-play mr-2"></i>Parse Arguments
</button>
</form>
</div>
</div>
</div>

<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
<script>
particlesJS('particles-js', {
"particles": {"number": {"value": 80, "density": {"enable": true, "value_area": 800}}, "color": {"value": "#ffffff"},
"shape": {"type": "circle", "stroke": {"width": 0}}, "opacity": {"value": 0.5}, "size": {"value": 3, "random": true},
"line_linked": {"enable": true, "distance": 150, "opacity": 0.4}, "move": {"enable": true, "speed": 6},
"interactivity": {"detect_on": "canvas", "events": {"onhover": {"enable": true}, "onclick": {"enable": true}}},
"retina_detect": true
});

document.getElementById('minimistForm').addEventListener('submit', function(e) {
e.preventDefault();
const argsStr = document.getElementById('args').value;
const args = argsStr.trim() ? argsStr.trim().split(/\s+/) : [];
fetch('/api/minimist', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ args })
})
.then(r => r.json())
.then(data => {
if (data.error) alert('Error: ' + data.error);
else alert('Parsed: ' + JSON.stringify(data.result, null, 2));
})
.catch(err => alert('Error: ' + err.message));
});
</script>
</body>
</html>
Loading
Loading