-
Notifications
You must be signed in to change notification settings - Fork 0
Claude/add sql injection nodegoat xtkqn #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| /* | ||
| * A1 - SQL Injection | ||
| * | ||
| * This module demonstrates SQL Injection vulnerabilities in a SQLite-backed | ||
| * payroll reports feature. User-supplied input is concatenated directly into | ||
| * SQL query strings instead of using parameterized queries. | ||
| * | ||
| * Attack examples: | ||
| * Search name: ' OR '1'='1 -> dumps all employee records | ||
| * Search name: ' OR 1=1-- -> bypasses filtering | ||
| * Search name: '; DROP TABLE employees;-- -> destructive injection | ||
| * Search name: ' UNION SELECT id,username,password,salary,0 FROM users-- -> data exfil | ||
| */ | ||
|
|
||
| const sqlite3 = require("sqlite3").verbose(); | ||
| const path = require("path"); | ||
|
|
||
| // Use an in-memory database pre-seeded with sample payroll data | ||
| let dbInstance = null; | ||
|
|
||
| function getDb() { | ||
| if (dbInstance) return dbInstance; | ||
|
|
||
| dbInstance = new sqlite3.Database(":memory:"); | ||
|
|
||
| dbInstance.serialize(() => { | ||
| // Create employees table with sensitive payroll data | ||
| dbInstance.run(` | ||
| CREATE TABLE IF NOT EXISTS employees ( | ||
| id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
| name TEXT NOT NULL, | ||
| department TEXT NOT NULL, | ||
| salary INTEGER NOT NULL, | ||
| ssn TEXT NOT NULL | ||
| ) | ||
| `); | ||
|
|
||
| // Create a shadow users table (exfiltrable via UNION injection) | ||
| dbInstance.run(` | ||
| CREATE TABLE IF NOT EXISTS users ( | ||
| id INTEGER PRIMARY KEY, | ||
| username TEXT NOT NULL, | ||
| password TEXT NOT NULL, | ||
| salary INTEGER, | ||
| is_admin INTEGER DEFAULT 0 | ||
| ) | ||
| `); | ||
|
|
||
| // Seed employees | ||
| const employees = [ | ||
| ["Alice Johnson", "Engineering", 95000, "123-45-6789"], | ||
| ["Bob Smith", "Marketing", 72000, "987-65-4321"], | ||
| ["Carol White", "HR", 68000, "456-78-9012"], | ||
| ["David Brown", "Finance", 88000, "321-54-9876"], | ||
| ["Eve Davis", "Engineering", 102000, "654-32-1098"] | ||
| ]; | ||
| const insertEmp = dbInstance.prepare( | ||
| "INSERT INTO employees (name, department, salary, ssn) VALUES (?, ?, ?, ?)" | ||
| ); | ||
| employees.forEach(e => insertEmp.run(e)); | ||
| insertEmp.finalize(); | ||
|
|
||
| // Seed users (simulates credential store accessible via UNION injection) | ||
| const users = [ | ||
| [1, "admin", "s3cr3tAdmin!", 0, 1], | ||
| [2, "user1", "Password123", 95000, 0], | ||
| [3, "user2", "qwerty", 72000, 0] | ||
| ]; | ||
| const insertUser = dbInstance.prepare( | ||
| "INSERT INTO users (id, username, password, salary, is_admin) VALUES (?, ?, ?, ?, ?)" | ||
| ); | ||
| users.forEach(u => insertUser.run(u)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential SQL injection in sqlite3 via string-based query concatenation - high severity Show fixRemediation: If possible, rebuild the query to use prepared statements or an ORM. If that is not possible, make sure the user input is verified or sanitized. To autofix all SQL injection instances in your entire app, install Zen for Node.js. Reply |
||
| insertUser.finalize(); | ||
| }); | ||
|
|
||
| return dbInstance; | ||
| } | ||
|
|
||
| /* ReportsDAO provides payroll search functionality */ | ||
| function ReportsDAO() { | ||
| "use strict"; | ||
|
|
||
| if (false === (this instanceof ReportsDAO)) { | ||
| console.log("Warning: ReportsDAO constructor called without 'new' operator"); | ||
| return new ReportsDAO(); | ||
| } | ||
|
|
||
| const db = getDb(); | ||
|
|
||
| /* | ||
| * VULNERABLE: searchEmployees builds a query via string concatenation. | ||
| * The `name` parameter comes directly from req.query.name with no | ||
| * sanitization or parameterization, allowing classic SQL injection. | ||
| * | ||
| * Fix (A1): Use a parameterized query instead: | ||
| * const query = "SELECT id, name, department, salary FROM employees WHERE name LIKE ?"; | ||
| * db.all(query, [`%${name}%`], callback); | ||
| */ | ||
| this.searchEmployees = (name, callback) => { | ||
| // Insecure: user input concatenated directly into SQL string | ||
| const query = `SELECT id, name, department, salary FROM employees WHERE name LIKE '%${name}%'`; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential SQL injection via string-based query concatenation - critical severity Show fixRemediation: If possible, rebuild the query to use prepared statements or an ORM. If that is not possible, make sure the user input is verified or sanitized. To autofix all SQL injection instances in your entire app, install Zen for Node.js. Reply |
||
|
|
||
| console.log(`[ReportsDAO] Executing query: ${query}`); | ||
|
|
||
| db.all(query, (err, rows) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential SQL injection in sqlite3 via string-based query concatenation - high severity Show fixRemediation: If possible, rebuild the query to use prepared statements or an ORM. If that is not possible, make sure the user input is verified or sanitized. To autofix all SQL injection instances in your entire app, install Zen for Node.js. Reply |
||
| if (err) { | ||
| return callback(err, null); | ||
| } | ||
| return callback(null, rows); | ||
| }); | ||
| }; | ||
|
|
||
| /* | ||
| * VULNERABLE: getEmployeeById fetches a single employee by ID using | ||
| * string interpolation. An attacker can inject UNION SELECT to exfiltrate | ||
| * data from other tables. | ||
| * | ||
| * Payload: 0 UNION SELECT id, username, password, is_admin FROM users-- | ||
| * | ||
| * Fix (A1): Use parameterized query: | ||
| * db.get("SELECT * FROM employees WHERE id = ?", [id], callback); | ||
| */ | ||
| this.getEmployeeById = (id, callback) => { | ||
| // Insecure: id from request URL parameter concatenated into query | ||
| const query = `SELECT * FROM employees WHERE id = ${id}`; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential SQL injection via string-based query concatenation - critical severity Show fixRemediation: If possible, rebuild the query to use prepared statements or an ORM. If that is not possible, make sure the user input is verified or sanitized. To autofix all SQL injection instances in your entire app, install Zen for Node.js. Reply |
||
|
|
||
| console.log(`[ReportsDAO] Executing query: ${query}`); | ||
|
|
||
| db.get(query, (err, row) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential SQL injection in sqlite3 via string-based query concatenation - high severity Show fixRemediation: If possible, rebuild the query to use prepared statements or an ORM. If that is not possible, make sure the user input is verified or sanitized. To autofix all SQL injection instances in your entire app, install Zen for Node.js. Reply |
||
| if (err) { | ||
| return callback(err, null); | ||
| } | ||
| return callback(null, row); | ||
| }); | ||
| }; | ||
| } | ||
|
|
||
| module.exports = { ReportsDAO }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| const { ReportsDAO } = require("../data/reports-dao"); | ||
| const { environmentalScripts } = require("../../config/config"); | ||
|
|
||
| function ReportsHandler() { | ||
| "use strict"; | ||
|
|
||
| const reportsDAO = new ReportsDAO(); | ||
|
|
||
| this.displayReports = (req, res, next) => { | ||
| const { userId } = req.session; | ||
|
|
||
| return res.render("payroll", { | ||
| userId, | ||
| employees: null, | ||
| searchName: "", | ||
| environmentalScripts | ||
| }); | ||
|
Comment on lines
+12
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Server-Side Template Injection via untrusted input in Show fixRemediation: Validate and sanitize all inputs before rendering, never pass raw user objects to templates, restrict template capabilities, and enforce strict variable whitelisting or safe rendering modes. Reply |
||
| }; | ||
|
|
||
| /* | ||
| * A1 - SQL Injection | ||
| * The search term from req.query.name is passed directly to ReportsDAO.searchEmployees | ||
| * which concatenates it into a raw SQL string. | ||
| * | ||
| * Attack: search for ' OR '1'='1 to dump all records. | ||
| * Attack: search for ' UNION SELECT id,username,password,salary,0 FROM users-- | ||
| * to exfiltrate the users table via a UNION-based injection. | ||
| * | ||
| * Fix: sanitize/validate input before passing to DAO, or use parameterized | ||
| * queries in the DAO layer (see comments in reports-dao.js). | ||
| */ | ||
| this.searchEmployees = (req, res, next) => { | ||
| const { userId } = req.session; | ||
| // Insecure: raw query parameter forwarded to DAO without sanitization | ||
| const searchName = req.query.name || ""; | ||
|
|
||
| reportsDAO.searchEmployees(searchName, (err, employees) => { | ||
| if (err) { | ||
| // Surface the raw DB error so attackers can observe schema info (A6) | ||
| return res.render("payroll", { | ||
| userId, | ||
| employees: [], | ||
| searchName, | ||
| dbError: err.message, | ||
| environmentalScripts | ||
| }); | ||
|
Comment on lines
+40
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Server-Side Template Injection via untrusted input in Show fixRemediation: Validate and sanitize all inputs before rendering, never pass raw user objects to templates, restrict template capabilities, and enforce strict variable whitelisting or safe rendering modes. Reply |
||
| } | ||
|
|
||
| return res.render("payroll", { | ||
| userId, | ||
| employees, | ||
| searchName, | ||
| environmentalScripts | ||
| }); | ||
|
Comment on lines
+49
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Server-Side Template Injection via untrusted input in Show fixRemediation: Validate and sanitize all inputs before rendering, never pass raw user objects to templates, restrict template capabilities, and enforce strict variable whitelisting or safe rendering modes. Reply |
||
| }); | ||
| }; | ||
|
|
||
| /* | ||
| * A1 - SQL Injection (second-order / numeric injection) | ||
| * The :id URL parameter is interpolated directly into a SQL query in the DAO. | ||
| * | ||
| * Attack: GET /reports/employee/0 UNION SELECT id,username,password,salary,0 FROM users-- | ||
| */ | ||
| this.getEmployee = (req, res, next) => { | ||
| const { userId } = req.session; | ||
| // Insecure: raw URL parameter passed to DAO without parseInt or validation | ||
| const empId = req.params.id; | ||
|
|
||
| reportsDAO.getEmployeeById(empId, (err, employee) => { | ||
| if (err) { | ||
| return res.render("payroll", { | ||
| userId, | ||
| employees: [], | ||
| searchName: "", | ||
| dbError: err.message, | ||
| environmentalScripts | ||
| }); | ||
|
Comment on lines
+71
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Server-Side Template Injection via untrusted input in Show fixRemediation: Validate and sanitize all inputs before rendering, never pass raw user objects to templates, restrict template capabilities, and enforce strict variable whitelisting or safe rendering modes. Reply |
||
| } | ||
|
|
||
| return res.render("payroll", { | ||
| userId, | ||
| employees: employee ? [employee] : [], | ||
| searchName: "", | ||
| environmentalScripts | ||
| }); | ||
|
Comment on lines
+80
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Server-Side Template Injection via untrusted input in Show fixRemediation: Validate and sanitize all inputs before rendering, never pass raw user objects to templates, restrict template capabilities, and enforce strict variable whitelisting or safe rendering modes. Reply |
||
| }); | ||
| }; | ||
| } | ||
|
|
||
| module.exports = ReportsHandler; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| {% extends "./layout.html" %} {% block title %}Payroll Reports{% endblock %} {% block content %} | ||
|
|
||
| <div class="row"> | ||
| <div class="col-lg-12"> | ||
|
|
||
| <div class="panel panel-default"> | ||
| <div class="panel-heading"> | ||
| <h3 class="panel-title">Employee Payroll Search</h3> | ||
| </div> | ||
| <div class="panel-body"> | ||
|
|
||
| <!-- A1 - SQL Injection: search input is concatenated into raw SQL --> | ||
| <form action="/reports" method="get" role="search"> | ||
| <div class="input-group"> | ||
| <input type="text" | ||
| class="form-control" | ||
| name="name" | ||
| placeholder="Search by employee name..." | ||
| value="{{ searchName }}"> | ||
| <span class="input-group-btn"> | ||
| <button class="btn btn-primary" type="submit"> | ||
| <i class="fa fa-search"></i> Search | ||
| </button> | ||
| </span> | ||
| </div> | ||
| <p class="help-block"> | ||
| <strong>Hint (A1 - SQL Injection):</strong> | ||
| Try searching for <code>' OR '1'='1</code> to dump all records, or | ||
| <code>' UNION SELECT id,username,password,salary,0 FROM users--</code> | ||
| to exfiltrate the users table. | ||
| </p> | ||
| </form> | ||
|
|
||
| </div> | ||
| </div> | ||
|
|
||
| {% if dbError %} | ||
| <div class="alert alert-danger"> | ||
| <strong>Database Error:</strong> {{ dbError }} | ||
| </div> | ||
| {% endif %} | ||
|
|
||
| {% if employees %} | ||
| <div class="panel panel-info"> | ||
| <div class="panel-heading"> | ||
| <h3 class="panel-title">Results</h3> | ||
| </div> | ||
| <div class="panel-body"> | ||
| <table class="table table-bordered table-hover"> | ||
| <thead> | ||
| <tr> | ||
| <th>ID</th> | ||
| <th>Name</th> | ||
| <th>Department</th> | ||
| <th>Salary</th> | ||
| <th>Actions</th> | ||
| </tr> | ||
| </thead> | ||
| <tbody> | ||
| {% for emp in employees %} | ||
| <tr> | ||
| <td>{{ emp.id }}</td> | ||
| <td>{{ emp.name }}</td> | ||
| <td>{{ emp.department }}</td> | ||
| <td>${{ emp.salary }}</td> | ||
| <td> | ||
| <!-- A1 - numeric injection: id goes straight into SQL --> | ||
| <a href="/reports/employee/{{ emp.id }}" class="btn btn-xs btn-info"> | ||
| View Detail | ||
| </a> | ||
| </td> | ||
| </tr> | ||
| {% endfor %} | ||
| </tbody> | ||
| </table> | ||
| </div> | ||
| </div> | ||
| {% endif %} | ||
|
|
||
| </div> | ||
| </div> | ||
| {% endblock %} |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 15 Open source vulnerabilities detected - critical severity DetailsRemediation Aikido suggests bumping the vulnerable packages to a safe version. Reply |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential SQL injection in sqlite3 via string-based query concatenation - high severity
SQL injection might be possible in these locations, especially if the strings being concatenated are controlled via user input.
Show fix
Remediation: If possible, rebuild the query to use prepared statements or an ORM. If that is not possible, make sure the user input is verified or sanitized. To autofix all SQL injection instances in your entire app, install Zen for Node.js.
Reply
@AikidoSec ignore: [REASON]to ignore this issue.More info