Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 3 additions & 221 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,221 +1,3 @@
const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const { exec } = require('child_process');
const fetch = require('node-fetch');
const db = require('./database');

const app = express();
const PORT = 3000;

// Middleware
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(express.static('public')); // Vulnerability: Directory listing might be enabled by default in some configurations or misconfigurations here
app.set('view engine', 'ejs');

// Vulnerability: Insecure usage of eval() for cookie handling (Insecure Deserialization simulation)
app.use((req, res, next) => {
if (req.cookies.preferences) {
try {
// DANGEROUS: deserializing undefined user input
const prefs = eval('(' + req.cookies.preferences + ')');
req.preferences = prefs;
} catch (e) {
console.error("Cookie parse error");
}
}
next();
});

// Debug endpoint (Vulnerability: Debug Mode Enabled)
app.get('/debug', (req, res) => {
res.json(process.env);
});

// Home
app.get('/', (req, res) => {
res.render('index');
});

// Login Page
app.get('/login', (req, res) => {
res.render('login', { error: null });
});

// Vulnerability: SQL Injection & Open Redirect
app.post('/login', (req, res) => {
const { username, password } = req.body;
const redirect = req.query.redirect; // Open Redirect potential

// VULNERABLE SQL QUERY
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;

console.log("Executing SQL: " + query);

db.get(query, (err, row) => {
if (err) {
return res.render('login', { error: "Database error" });
}
if (row) {
// Vulnerability: Weak Session Management (Predictable Cookie)
const sessionId = Buffer.from(row.username).toString('base64');
res.cookie('session', sessionId);
res.cookie('role', row.role); // Vulnerability: Client-side role storage (Broken Access Control)

if (redirect) {
return res.redirect(redirect);
}
return res.redirect('/dashboard');
} else {
res.render('login', { error: "Invalid credentials" });
}
});
});

// Logout
app.get('/logout', (req, res) => {
res.clearCookie('session');
res.clearCookie('role');
res.redirect('/');
});

// Register Page
app.get('/register', (req, res) => {
res.render('register');
});

// Vulnerability: Mass Assignment
app.post('/register', (req, res) => {
const columns = Object.keys(req.body).join(', ');
const values = Object.values(req.body).map(v => `'${v}'`).join(', ');

// Very dangerous construction allows passing 'role' in body
const query = `INSERT INTO users (${columns}) VALUES (${values})`;

db.run(query, function (err) {
if (err) {
return res.send("Error registering: " + err.message);
}
res.redirect('/login');
});
});

// Dashboard - Vulnerability: Reflected XSS
app.get('/dashboard', (req, res) => {
if (!req.cookies.session) return res.redirect('/login');

const query = req.query.q;
let message = "Welcome to the dashboard.";
if (query) {
// VULNERABLE: Direct injection of query parameter
message = `You searched for: ${query}`;
}

// Fetch all users for the list
db.all("SELECT * FROM users", (err, users) => {
res.render('dashboard', { message, users, user: { username: Buffer.from(req.cookies.session, 'base64').toString() } });
});
});

// Profile - Vulnerability: IDOR, Stored XSS
app.get('/profile', (req, res) => {
if (!req.cookies.session) return res.redirect('/login');

const id = req.query.id; // IDOR: Can view any user's profile

if (!id) {
// Default to current user (simulated logic)
// In real app we'd look up by session, but here we force using ?id= for demo of IDOR
return res.send("Please provide a profile ID (e.g., ?id=1)");
}

db.get(`SELECT * FROM users WHERE id = ${id}`, (err, row) => { // also SQLi possible here
if (err || !row) return res.send("User not found");
res.render('profile', { profileUser: row });
});
});

// Update Profile - Vulnerability: CSRF (no token), IDOR (in body)
app.post('/profile/update', (req, res) => {
const { id, bio } = req.body;

// VULNERABLE: Updates ANY user based on ID in body
// VULNERABLE: Stored XSS in 'bio'
const stmt = db.prepare("UPDATE users SET bio = ? WHERE id = ?");
stmt.run(bio, id, (err) => {
res.redirect(`/profile?id=${id}`);
});
});

// File Upload - Vulnerability: Unrestricted File Upload
const storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, 'public/uploads/'),
filename: (req, file, cb) => cb(null, file.originalname) // VULNERABLE: Keeps original name (e.g. shell.php)
});
const upload = multer({ storage: storage });

app.post('/upload', upload.single('profile_pic'), (req, res) => {
const userId = req.body.userId;
const filePath = `/uploads/${req.file.originalname}`;

db.run("UPDATE users SET profile_pic = ? WHERE id = ?", [filePath, userId], (err) => {
res.redirect(`/profile?id=${userId}`);
});
});

// Admin Panel - Vulnerability: Broken Access Control, Command Injection
app.get('/admin', (req, res) => {
// VULNERABLE: Trusting the cookie
if (req.cookies.role !== 'admin') {
return res.status(403).send("Access Denied");
}
res.render('admin');
});

app.post('/admin/health', (req, res) => {
if (req.cookies.role !== 'admin') return res.status(403).send("Access Denied");

const target = req.body.target;
// VULNERABLE: Command Injection
exec(`ping -c 1 ${target}`, (error, stdout, stderr) => {
res.send(`<pre>${stdout || stderr || error}</pre>`);
});
});

// API - Vulnerability: Sensitive Data Exposure
app.get('/api/users', (req, res) => {
db.all("SELECT * FROM users", (err, rows) => {
res.json(rows); // Returns passwords and everything
});
});

// File Download - Vulnerability: Path Traversal
app.get('/download', (req, res) => {
const filename = req.query.file;
// VULNERABLE: No validation on filename
const fPath = path.join(__dirname, 'public/uploads', filename);
res.download(fPath);
});

// SSRF Endpoint
app.get('/fetch-url', (req, res) => {
const url = req.query.url;
// VULNERABLE: SSRF
fetch(url)
.then(response => response.text())
.then(body => res.send(body))
.catch(err => res.send(err.message));
});

// Hardcoded Secrets (Visible in source code analysis)
// AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"
// AWS_SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
# Security Fix for RED-SAST-101912-2
# TODO: Manual fix required
pass