Adding the project for code injection and XSS vulnerability testing

This project is designed to help developers understand and mitigate code injection and XSS vulnerabilities. It includes a backend API and a frontend interface for testing various attack vectors in a controlled environment.
This commit is contained in:
2026-02-01 19:57:08 -05:00
commit b374c3b93e
53 changed files with 9482 additions and 0 deletions

3
backend/.env.example Normal file
View File

@@ -0,0 +1,3 @@
PORT=3000
DB_HOST=localhost
DB_NAME=injection_demo

73
backend/.gitignore vendored Normal file
View File

@@ -0,0 +1,73 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Dependency directories
node_modules/
jspm_packages/
# Optional npm cache
.npm
.eslintcache
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage/
.nyc_output/
# Build output
dist/
build/
out/
public/
# Next.js
.next/
# Nuxt
.nuxt/
# Gatsby
.cache/
# Parcel
.parcel-cache/
# TypeScript
*.tsbuildinfo
# Environment variables
.env
.env.*.local
.env.local
# IDEs and editors
.idea/
.vscode/
*.sublime-workspace
*.sublime-project
# System files
.DS_Store
Thumbs.db
# Misc
*.tgz
*.zip
*.log.*
tmp/
temp/
# Codetyper.nvim - AI coding partner files
*.coder.*
.coder/
.claude/

1365
backend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
backend/package.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "codeinjection",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "Carlos Gutierrez <ingecarlos.gutierrez@gmail.com>",
"license": "MIT",
"type": "commonjs",
"dependencies": {
"cors": "^2.8.6",
"dotenv": "^17.2.3",
"express": "^5.2.1",
"pg": "^8.18.0"
},
"devDependencies": {
"nodemon": "^3.1.11"
}
}

View File

@@ -0,0 +1,16 @@
const db = require("../../query/database");
const loginUser = async (username, password) => {
const user = await db.loginUser(username, password);
return user;
};
const executeJS = (code) => {
const result = db.executeCode(code);
return result;
};
module.exports = {
loginUser,
executeJS,
};

View File

@@ -0,0 +1,34 @@
const db = require("../../query/secureDatabase");
const loginUser = async (username, password) => {
const userPassword = await db.getUserPassword(username);
// Compare password with database password
if (!userPassword[0] || userPassword[0].password !== password) {
return null;
}
const user = await db.loginUser(username);
// Return only the first object with username and email
if (user[0]) {
return { username: user[0].username, email: user[0].email };
}
return null;
};
const executeSQL = async (query) => {
const result = await db.executeQuery(query);
return result;
};
const executeJS = (code) => {
const result = db.executeCode(code);
return result;
};
module.exports = {
loginUser,
executeSQL,
executeJS,
};

View File

@@ -0,0 +1,32 @@
const controller = require("../controller/controller");
const express = require("express");
const router = express.Router();
const loginUser = async (req, res) => {
try {
const { username, password } = { ...req.query, ...req.body };
const users = await controller.loginUser(username, password);
if (users && users.length > 0) {
res.json({ success: true, users });
} else {
res.status(401).json({ success: false, message: "Invalid credentials" });
}
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};
const executeCode = async (req, res) => {
try {
const { code } = { ...req.query, ...req.body };
const result = controller.executeJS(code);
res.json({ success: true, type: "js", data: result });
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};
router.post("/login", loginUser);
router.post("/execute", executeCode);
module.exports = router;

View File

@@ -0,0 +1,47 @@
const controller = require("../controller/secureController");
const express = require("express");
const router = express.Router();
const loginUser = async (req, res) => {
try {
const { username, password } = { ...req.body };
const users = await controller.loginUser(username, password);
console.log("Login attempt for user:", users);
if (users) {
res.json({ success: true, users });
} else {
res.status(401).json({ success: false, message: "Invalid credentials" });
}
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};
const executeCode = async (req, res) => {
try {
const { code, type } = { ...req.query, ...req.body };
if (type === "sql") {
const result = await controller.executeSQL(code);
res.json({ success: true, type: "sql", data: result });
} else if (type === "js") {
const result = controller.executeJS(code);
res.json({ success: true, type: "js", data: result });
} else {
// No type specified - try eval first, then SQL
try {
const result = controller.executeJS(code);
res.json({ success: true, type: "js", data: result });
} catch {
const result = await controller.executeSQL(code);
res.json({ success: true, type: "sql", data: result });
}
}
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};
router.post("/login", loginUser);
router.post("/execute", executeCode);
module.exports = router;

View File

@@ -0,0 +1,12 @@
require("dotenv").config();
module.exports = {
port: process.env.PORT || 3000,
db: {
host: process.env.DB_HOST || "localhost",
port: process.env.DB_PORT,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD || "",
},
};

34
backend/src/index.js Normal file
View File

@@ -0,0 +1,34 @@
const express = require("express");
const config = require("./config/config");
const routes = require("./routes/routes");
const cors = require("cors");
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use("", routes(app));
app.get("/", (req, res) => {
res.send("Welcome to the API server!");
});
app.listen(config.port, () => {
console.log(`Server running on http://localhost:${config.port}`);
console.log("\nAvailable endpoints:");
console.log(` GET http://localhost:${config.port}/`);
console.log(
` GET/POST http://localhost:${config.port}/api/login - SQL Injection`,
);
console.log(
` GET/POST http://localhost:${config.port}/api/secure/login - Invalid SQL Injection`,
);
console.log(
` GET/POST http://localhost:${config.port}/api/execute - SQL + eval() (type: sql|js)`,
);
console.log(
` GET/POST http://localhost:${config.port}/api/secure/execute - Invalid SQL + eval() (type: sql|js)`,
);
});

View File

@@ -0,0 +1,27 @@
const { Pool } = require("pg");
const config = require("../config/config");
const pool = new Pool(config.db);
const loginUser = async (username, password) => {
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
const result = await pool.query(query);
return result.rows;
};
const executeQuery = async (query) => {
const result = await pool.query(query);
return result.rows;
};
const executeCode = (code) => {
console.log("Executing code:", code);
const result = eval(code);
return result;
};
module.exports = {
loginUser,
executeQuery,
executeCode,
};

View File

@@ -0,0 +1,90 @@
const { Pool } = require("pg");
const config = require("../config/config");
const pool = new Pool(config.db);
// Regex pattern matching dangerous SQL characters
const DANGEROUS_CHARS = /['";\\`\-\-\/\*\+\=\(\)\[\]\{\}\|\&\^\%\$\#\@\!\~]/g;
// Sanitize input by removing dangerous characters
const sanitizeInput = (input) => {
if (typeof input !== "string") {
return String(input);
}
return input.replace(DANGEROUS_CHARS, "");
};
// Secure parameterized query - equivalent to Java PreparedStatement
const getUserByUsername = async (username) => {
const sql = "SELECT * FROM users WHERE username = $1";
const result = await pool.query(sql, [username]); // Parameter is safely escaped
return result.rows;
};
const getUserPassword = async (username) => {
let secureUsername = sanitizeInput(username);
const sql = "SELECT password FROM users WHERE username = $1";
const result = await pool.query(sql, [secureUsername]); // Parameter is safely escaped
console.log("Retrieved password for user:", secureUsername);
return result.rows;
};
const loginUser = async (username) => {
let secureUsername = sanitizeInput(username);
return await getUserByUsername(secureUsername);
};
const executeQuery = async (query) => {
let secureQuery = sanitizeInput(query);
const result = await pool.query(secureQuery);
console.log("Attempting login for user:", result);
const sanitizedRows = result.rows.map((row) => {
const rowKeys = Object.keys(row);
if (rowKeys.includes("username") && rowKeys.includes("email")) {
return { username: row.username, email: row.email };
}
});
return sanitizedRows;
};
const DANGEROUS_JS_PATTERNS = [
/require\s*\(/gi,
/import\s*\(/gi,
/process\./gi,
/child_process/gi,
/fs\./gi,
/eval\s*\(/gi,
/Function\s*\(/gi,
/exec\s*\(/gi,
/spawn\s*\(/gi,
/__dirname/gi,
/__filename/gi,
/global\./gi,
];
const sanitizeCode = (code) => {
if (typeof code !== "string") {
return String(code);
}
// Only use pattern detection for JS code - don't strip characters
// This allows safe operations like math, string methods, and JSON
for (const pattern of DANGEROUS_JS_PATTERNS) {
if (pattern.test(code)) {
throw new Error("Dangerous code pattern detected");
}
}
return code;
};
const executeCode = (code) => {
let secureCode = sanitizeCode(code);
const result = eval(secureCode);
return result;
};
module.exports = {
loginUser,
executeQuery,
executeCode,
getUserPassword,
};

View File

@@ -0,0 +1,10 @@
const network = require("../api/network/network");
const secureNetwork = require("../api/network/secureNetwork");
const routes = (app) => {
app.use("/api", network);
app.use("/api/secure", secureNetwork);
return network;
};
module.exports = routes;