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
74 changes: 74 additions & 0 deletions SAST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,77 @@ module.exports = function searchProducts () {
})
}
}

/*
* Copyright (c) 2014-2023 Bjoern Kimminich & the OWASP Juice Shop contributors.
* SPDX-License-Identifier: MIT
*/

import models = require('../models/index')
import { type Request, type Response, type NextFunction } from 'express'
import { UserModel } from '../models/user'

import * as utils from '../lib/utils'
const challengeUtils = require('../lib/challengeUtils')
const challenges = require('../data/datacache').challenges

class ErrorWithParent extends Error {
parent: Error | undefined
}

// vuln-code-snippet start unionSqlInjectionChallenge dbSchemaChallenge
module.exports = function searchProducts () {
return (req: Request, res: Response, next: NextFunction) => {
let criteria: any = req.query.q === 'undefined' ? '' : req.query.q ?? ''
criteria = (criteria.length <= 200) ? criteria : criteria.substring(0, 200)
models.sequelize.query(`SELECT * FROM Products WHERE ((name LIKE '%${criteria}%' OR description LIKE '%${criteria}%') AND deletedAt IS NULL) ORDER BY name`) // vuln-code-snippet vuln-line unionSqlInjectionChallenge dbSchemaChallenge
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cycode: SAST violation: 'Unsanitized input in SQL query'.

Severity: Critical

Description

Using unsanitized data, such as user input or request data, or externally influenced data passed to a function, in SQL query exposes your application to SQL injection attacks. This vulnerability arises when externally controlled data is directly included in SQL statements without proper sanitation, allowing attackers to manipulate queries and access or modify data.

Company Remediation Guideline

Please see http://www.espn.com for more information on we would prefer to have you mitigate this violation.

🎥 Learning materials (by Secure Code Warrior)


Tell us what how you wish to proceed using one of the following commands:

Tag Short Description
#cycode_sast_false_positive Mark as false positive — applies to this violation only
#cycode_ai_remediation Request remediation guidance using Cycode AI
#cycode_sast_ignore_here Ignore this violation — applies to this violation only

⚠️ When commenting on Github, you may need to refresh the page to see the latest updates.

.then(([products]: any) => {
const dataString = JSON.stringify(products)
if (challengeUtils.notSolved(challenges.unionSqlInjectionChallenge)) { // vuln-code-snippet hide-start
let solved = true
UserModel.findAll().then(data => {
const users = utils.queryResultToJson(data)
if (users.data?.length) {
for (let i = 0; i < users.data.length; i++) {
solved = solved && utils.containsOrEscaped(dataString, users.data[i].email) && utils.contains(dataString, users.data[i].password)
if (!solved) {
break
}
}
if (solved) {
challengeUtils.solve(challenges.unionSqlInjectionChallenge)
}
}
}).catch((error: Error) => {
next(error)
})
}
if (challengeUtils.notSolved(challenges.dbSchemaChallenge)) {
let solved = true
models.sequelize.query('SELECT sql FROM sqlite_master').then(([data]: any) => {
const tableDefinitions = utils.queryResultToJson(data)
if (tableDefinitions.data?.length) {
for (let i = 0; i < tableDefinitions.data.length; i++) {
if (tableDefinitions.data[i].sql) {
solved = solved && utils.containsOrEscaped(dataString, tableDefinitions.data[i].sql)
if (!solved) {
break
}
}
}
if (solved) {
challengeUtils.solve(challenges.dbSchemaChallenge)
}
}
})
} // vuln-code-snippet hide-end
for (let i = 0; i < products.length; i++) {
products[i].name = req.__(products[i].name)
products[i].description = req.__(products[i].description)
}
res.json(utils.queryResultToJson(products))
}).catch((error: ErrorWithParent) => {
next(error.parent)
})
}
}