Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 74 additions & 31 deletions app.js
Original file line number Diff line number Diff line change
@@ -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

Check warning on line 18 in app.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app.js#L18

Require statement not part of import statement.
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var log4js = require("log4js");
var bodyParser = require('body-parser'); // Parse incoming request bodies

Check warning on line 20 in app.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app.js#L20

Require statement not part of import statement.
var log4js = require("log4js"); // Application logging framework

Check warning on line 21 in app.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app.js#L21

Require statement not part of import statement.

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

Check warning on line 24 in app.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app.js#L24

Require statement not part of import statement.
var login = require('./routes/login'); // Authentication routes

Check warning on line 25 in app.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app.js#L25

Require statement not part of import statement.
var products = require('./routes/products'); // Product management routes

Check warning on line 26 in app.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app.js#L26

Require statement not part of import statement.

// 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

Check warning on line 77 in app.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app.js#L77

A hard-coded credential was detected.
cookie: {
secure: false,
maxAge: 99999999999
secure: false, // VULNERABLE: Cookies not restricted to HTTPS
maxAge: 99999999999 // VULNERABLE: Extremely long session lifetime

Check warning on line 80 in app.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app.js#L80

The numeric literal '99999999999' will have at different value at runtime.
}
}));

/*
* 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;
34 changes: 26 additions & 8 deletions config.js
Original file line number Diff line number Diff line change
@@ -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){
Expand All @@ -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;
37 changes: 31 additions & 6 deletions dummy.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,47 @@
// 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",
"password": "asdfpiuw981"
}
],

/**
* 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"
},
{
Expand All @@ -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"
},
{
Expand All @@ -65,4 +89,5 @@ var dummy_info = {
]
}

// Export dummy data object
module.exports = dummy_info;
30 changes: 30 additions & 0 deletions model/auth.js
Original file line number Diff line number Diff line change
@@ -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;
Loading