Endpoint: {{ endpoint }} with {{ endpoint.active_findings|length|apnumber }}
diff --git a/dojo/tools/progpilot/parser.py b/dojo/tools/progpilot/parser.py
index e6a5d4b7a49..9947976e6ee 100644
--- a/dojo/tools/progpilot/parser.py
+++ b/dojo/tools/progpilot/parser.py
@@ -15,9 +15,9 @@ def get_description_for_scan_types(self, scan_type):
def get_findings(self, filename, test):
findings = []
- description = ""
results = json.load(filename)
for result in results:
+ description = ""
source_name = result.get("source_name", None)
source_line = result.get("source_line", None)
source_column = result.get("source_column", None)
diff --git a/dojo/tools/sarif/parser.py b/dojo/tools/sarif/parser.py
index 59dae7da29a..2fe52197b15 100644
--- a/dojo/tools/sarif/parser.py
+++ b/dojo/tools/sarif/parser.py
@@ -416,10 +416,16 @@ def get_item(result, rules, artifacts, run_date):
# Some tools such as GitHub or Grype return the severity in properties
# instead
if "properties" in rule and "security-severity" in rule["properties"]:
- cvss = float(rule["properties"]["security-severity"])
- severity = cvss_to_severity(cvss)
- finding.cvssv3_score = cvss
- finding.severity = severity
+ try:
+ cvss = float(rule["properties"]["security-severity"])
+ severity = cvss_to_severity(cvss)
+ finding.cvssv3_score = cvss
+ finding.severity = severity
+ except ValueError:
+ if rule["properties"]["security-severity"].lower().capitalize() in ["Info", "Low", "Medium", "High", "Critical"]:
+ finding.severity = rule["properties"]["security-severity"].lower().capitalize()
+ else:
+ finding.severity = "Info"
# manage the case that some tools produce CWE as properties of the result
cwes_properties_extracted = get_result_cwes_properties(result)
diff --git a/helm/defectdojo/Chart.lock b/helm/defectdojo/Chart.lock
index b072c638d52..94b4d519453 100644
--- a/helm/defectdojo/Chart.lock
+++ b/helm/defectdojo/Chart.lock
@@ -4,15 +4,15 @@ dependencies:
version: 9.19.1
- name: postgresql
repository: https://charts.bitnami.com/bitnami
- version: 15.3.1
+ version: 15.3.3
- name: postgresql-ha
repository: https://charts.bitnami.com/bitnami
version: 9.4.11
- name: rabbitmq
repository: https://charts.bitnami.com/bitnami
- version: 14.1.3
+ version: 14.1.5
- name: redis
repository: https://charts.bitnami.com/bitnami
- version: 19.3.1
-digest: sha256:199b9657d0824c026d020566645be242d0c50064725fb51d2a3943f2a2d70ce3
-generated: "2024-05-13T17:46:25.393404332Z"
+ version: 19.3.4
+digest: sha256:bda9c0c13031232331f49aa76f4614e03fa714d17dffdd069f8ab615551c84ff
+generated: "2024-05-20T18:42:15.880031454Z"
diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml
index c205e4ea550..1d82f925c72 100644
--- a/helm/defectdojo/Chart.yaml
+++ b/helm/defectdojo/Chart.yaml
@@ -2,7 +2,7 @@ apiVersion: v2
appVersion: "2.35.0-dev"
description: A Helm chart for Kubernetes to install DefectDojo
name: defectdojo
-version: 1.6.130-dev
+version: 1.6.131-dev
icon: https://www.defectdojo.org/img/favicon.ico
maintainers:
- name: madchap
diff --git a/unittests/scans/sarif/issue_10191.json b/unittests/scans/sarif/issue_10191.json
new file mode 100644
index 00000000000..88bad7f5b38
--- /dev/null
+++ b/unittests/scans/sarif/issue_10191.json
@@ -0,0 +1,2997 @@
+{
+ "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/schemas/sarif-schema-2.1.0.json",
+ "runs": [
+ {
+ "invocations": [
+ {
+ "executionSuccessful": true,
+ "toolExecutionNotifications": [
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/weakPasswordChallenge_4.ts:1:\n `User.init(\n password: {\n type: DataTypes.STRING,\n set (clearTextPassword) {\n validatePasswordIsNotInTopOneMillionCommonPasswordsList(clearTextPassword)\n this.setDataValue('password', security.hash(clearTextPassword))\n }\n },` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/weakPasswordChallenge_3.ts:1:\n `User.init(\n password: {\n type: DataTypes.STRING,\n set (clearTextPassword) {\n validatePasswordHasAtLeastOneNumber(clearTextPassword)\n validatePasswordHasAtLeastOneSpecialChar(clearTextPassword)\n validatePasswordHasAtLeastOneUpperCaseChar(clearTextPassword)\n validatePasswordHasAtLeastOneLowerCaseChar(clearTextPassword)\n validatePasswordHasAtLeastTenChar(clearTextPassword)\n this.setDataValue('password', security.hash(clearTextPassword))\n }\n },` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/tokenSaleChallenge_3_correct.ts:14:\n `]` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/registerAdminChallenge_4.ts:1:\n `/* Generated API endpoints */\n finale.initialize({ app, sequelize })\n\n const autoModels = [\n { name: 'User', exclude: ['password', 'totpSecret', 'role'], model: UserModel },\n { name: 'Product', exclude: [], model: ProductModel },\n { name: 'Feedback', exclude: [], model: FeedbackModel },\n { name: 'BasketItem', exclude: [], model: BasketItemModel },\n { name: 'Challenge', exclude: [], model: ChallengeModel },\n { name: 'Complaint', exclude: [], model: ComplaintModel },\n { name: 'Recycle', exclude: [], model: RecycleModel },\n { name: 'SecurityQuestion', exclude: [], model: SecurityQuestionModel },\n { name: 'SecurityAnswer', exclude: [], model: SecurityAnswerModel },\n { name: 'Address', exclude: [], model: AddressModel },\n { name: 'PrivacyRequest', exclude: [], model: PrivacyRequestModel },\n { name: 'Card', exclude: [], model: CardModel },\n { name: 'Quantity', exclude: [], model: QuantityModel }\n ]\n\n for (const { name, exclude, model } of autoModels) {\n const resource = finale.resource({\n model,\n endpoints: [`/api/${name}s`, `/api/${name}s/:id`],\n excludeAttributes: exclude,\n pagination: false\n })\n\n // create a wallet when a new user is registered using API\n if (name === 'User') {\n resource.create.send.before((req: Request, res: Response, context: { instance: { id: any }, continue: any }) => {\n WalletModel.create({ UserId: context.instance.id }).catch((err: unknown) => {\n console.log(err)\n })\n return context.continue\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginAdminChallenge_3.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = $1 AND password = $2 AND deletedAt IS NULL`,\n { bind: [ req.body.email, req.body.password ], model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/registerAdminChallenge_3_correct.ts:1:\n `/* Generated API endpoints */\n finale.initialize({ app, sequelize })\n\n const autoModels = [\n { name: 'User', exclude: ['password', 'totpSecret'], model: UserModel },\n { name: 'Product', exclude: [], model: ProductModel },\n { name: 'Feedback', exclude: [], model: FeedbackModel },\n { name: 'BasketItem', exclude: [], model: BasketItemModel },\n { name: 'Challenge', exclude: [], model: ChallengeModel },\n { name: 'Complaint', exclude: [], model: ComplaintModel },\n { name: 'Recycle', exclude: [], model: RecycleModel },\n { name: 'SecurityQuestion', exclude: [], model: SecurityQuestionModel },\n { name: 'SecurityAnswer', exclude: [], model: SecurityAnswerModel },\n { name: 'Address', exclude: [], model: AddressModel },\n { name: 'PrivacyRequest', exclude: [], model: PrivacyRequestModel },\n { name: 'Card', exclude: [], model: CardModel },\n { name: 'Quantity', exclude: [], model: QuantityModel }\n ]\n\n for (const { name, exclude, model } of autoModels) {\n const resource = finale.resource({\n model,\n endpoints: [`/api/${name}s`, `/api/${name}s/:id`],\n excludeAttributes: exclude,\n pagination: false\n })\n\n // create a wallet when a new user is registered using API\n if (name === 'User') {\n resource.create.send.before((req: Request, res: Response, context: { instance: { id: any }, continue: any }) => {\n WalletModel.create({ UserId: context.instance.id }).catch((err: unknown) => {\n console.log(err)\n })\n context.instance.role = 'customer'\n return context.continue\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginBenderChallenge_4.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = '${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`, { model: models.User, plain: false })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginBenderChallenge_2_correct.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = $mail AND password = $pass AND deletedAt IS NULL`,\n { bind: { mail: req.body.email, pass: security.hash(req.body.password) }, model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/registerAdminChallenge_1.ts:1:\n `/* Generated API endpoints */\n finale.initialize({ app, sequelize })\n\n const autoModels = [\n { name: 'User', exclude: ['password', 'totpSecret'], model: UserModel },\n { name: 'Product', exclude: [], model: ProductModel },\n { name: 'Feedback', exclude: [], model: FeedbackModel },\n { name: 'BasketItem', exclude: [], model: BasketItemModel },\n { name: 'Challenge', exclude: [], model: ChallengeModel },\n { name: 'Complaint', exclude: [], model: ComplaintModel },\n { name: 'Recycle', exclude: [], model: RecycleModel },\n { name: 'SecurityQuestion', exclude: [], model: SecurityQuestionModel },\n { name: 'SecurityAnswer', exclude: [], model: SecurityAnswerModel },\n { name: 'Address', exclude: [], model: AddressModel },\n { name: 'PrivacyRequest', exclude: [], model: PrivacyRequestModel },\n { name: 'Card', exclude: [], model: CardModel },\n { name: 'Quantity', exclude: [], model: QuantityModel }\n ]\n\n for (const { name, exclude, model } of autoModels) {\n const resource = finale.resource({\n model,\n endpoints: [`/api/${name}s`, `/api/${name}s/:id`],\n excludeAttributes: exclude,\n pagination: false\n })\n\n // create a wallet when a new user is registered using API\n if (name === 'User') {\n resource.create.send.before((req: Request, res: Response, context: { instance: { id: any }, continue: any }) => {\n WalletModel.create({ UserId: context.instance.id }).catch((err: unknown) => {\n console.log(err)\n })\n context.instance.role = context.instance.role ? context.instance.role : 'customer'\n return context.continue\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/restfulXssChallenge_3.ts:43:\n `: any[]` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginAdminChallenge_1.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (req.body.email.match(/.*['-;].*/) || req.body.password.match(/.*['-;].*/)) {\n res.status(451).send(res.__('SQL Injection detected.'))\n }\n models.sequelize.query(`SELECT * FROM Users WHERE email = '${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`, { model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginBenderChallenge_1.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (req.body.email.match(/.*['-;].*/) || req.body.password.match(/.*['-;].*/)) {\n res.status(451).send(res.__('SQL Injection detected.'))\n }\n models.sequelize.query(`SELECT * FROM Users WHERE email = '${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`, { model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginJimChallenge_4.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (req.body.email.match(/.*['-;].*/) || req.body.password.match(/.*['-;].*/)) {\n res.status(451).send(res.__('SQL Injection detected.'))\n }\n models.sequelize.query(`SELECT * FROM Users WHERE email = '${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`, { model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/restfulXssChallenge_2.ts:57:\n `: any[]` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line frontend/src/app/Services/user.service.ts:14:\n `new?:` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Timeout"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Timeout when running vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.dos.rules_lgpl_javascript_dos_rule-regex-dos on server.ts:\n "
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/weakPasswordChallenge_1_correct.ts:1:\n `User.init(\n password: {\n type: DataTypes.STRING,\n set (clearTextPassword) {\n validatePasswordHasAtLeastTenChar(clearTextPassword)\n validatePasswordIsNotInTopOneMillionCommonPasswordsList(clearTextPassword)\n this.setDataValue('password', security.hash(clearTextPassword))\n }\n },` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/weakPasswordChallenge_2.ts:1:\n `User.init(\n password: {\n type: DataTypes.STRING,\n set (clearTextPassword) {\n validatePasswordHasAtLeastOneNumber(clearTextPassword)\n validatePasswordHasAtLeastOneSpecialChar(clearTextPassword)\n validatePasswordHasAtLeastOneUpperCaseChar(clearTextPassword)\n validatePasswordHasAtLeastOneLowerCaseChar(clearTextPassword)\n validatePasswordHasAtLeastTenChar(clearTextPassword)\n validatePasswordIsNotInTopOneMillionCommonPasswordsList(clearTextPassword)\n this.setDataValue('password', security.hash(clearTextPassword))\n }\n },` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/registerAdminChallenge_2.ts:1:\n `/* Generated API endpoints */\n finale.initialize({ app, sequelize })\n\n const autoModels = [\n { name: 'Product', exclude: [], model: ProductModel },\n { name: 'Feedback', exclude: [], model: FeedbackModel },\n { name: 'BasketItem', exclude: [], model: BasketItemModel },\n { name: 'Challenge', exclude: [], model: ChallengeModel },\n { name: 'Complaint', exclude: [], model: ComplaintModel },\n { name: 'Recycle', exclude: [], model: RecycleModel },\n { name: 'SecurityQuestion', exclude: [], model: SecurityQuestionModel },\n { name: 'SecurityAnswer', exclude: [], model: SecurityAnswerModel },\n { name: 'Address', exclude: [], model: AddressModel },\n { name: 'PrivacyRequest', exclude: [], model: PrivacyRequestModel },\n { name: 'Card', exclude: [], model: CardModel },\n { name: 'Quantity', exclude: [], model: QuantityModel }\n ]\n\n for (const { name, exclude, model } of autoModels) {\n const resource = finale.resource({\n model,\n endpoints: [`/api/${name}s`, `/api/${name}s/:id`],\n excludeAttributes: exclude,\n pagination: false\n })` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginJimChallenge_3.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = ? AND password = ? AND deletedAt IS NULL`,\n { replacements: [ req.body.email, req.body.password ], model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginJimChallenge_2.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = '${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`, { model: models.User, plain: false })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginJimChallenge_1_correct.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = $1 AND password = $2 AND deletedAt IS NULL`,\n { bind: [ req.body.email, security.hash(req.body.password) ], model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginAdminChallenge_4_correct.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = $1 AND password = $2 AND deletedAt IS NULL`,\n { bind: [ req.body.email, security.hash(req.body.password) ], model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginAdminChallenge_2.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = $1 AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`,\n { bind: [ req.body.email ], model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/loginBenderChallenge_3.ts:1:\n `import {BasketModel} from \"../../../models/basket\";\n\nmodule.exports = function login () {\n function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {\n BasketModel.findOrCreate({ where: { UserId: user.data.id } })\n .then(([basket]: [BasketModel, boolean]) => {\n const token = security.authorize(user)\n user.bid = basket.id // keep track of original basket\n security.authenticatedUsers.put(token, user)\n res.json({ authentication: { token, bid: basket.id, umail: user.data.email } })\n }).catch((error: Error) => {\n next(error)\n })\n }\n\n return (req: Request, res: Response, next: NextFunction) => {\n models.sequelize.query(`SELECT * FROM Users WHERE email = :mail AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`,\n { replacements: { mail: req.body.email }, model: models.User, plain: true })\n .then((authenticatedUser: { data: User }) => {\n const user = utils.queryResultToJson(authenticatedUser)\n if (user.data?.id && user.data.totpSecret !== '') {\n res.status(401).json({\n status: 'totp_token_required',\n data: {\n tmpToken: security.authorize({\n userId: user.data.id,\n type: 'password_valid_needs_second_factor_token'\n })\n }\n })\n } else if (user.data?.id) {\n afterLogin(user, res, next)\n } else {\n res.status(401).send(res.__('Invalid email or password.'))\n }\n }).catch((error: Error) => {\n next(error)\n })\n }` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/tokenSaleChallenge_1.ts:18:\n `]` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/tokenSaleChallenge_2.ts:19:\n `]` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Syntax error"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Syntax error at line data/static/codefixes/restfulXssChallenge_4.ts:57:\n `: any[]` was unexpected"
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Timeout"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Timeout when running vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.eval.rules_lgpl_javascript_eval_rule-eval-require on frontend/src/assets/private/three.js:\n "
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Timeout"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Timeout when running vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.redirect.rules_lgpl_javascript_redirect_rule-express-open-redirect2 on frontend/src/assets/private/three.js:\n "
+ }
+ },
+ {
+ "descriptor": {
+ "id": "Timeout"
+ },
+ "level": "warning",
+ "message": {
+ "text": "Timeout when running vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.xml.rules_lgpl_javascript_xml_rule-node-xpath-injection on frontend/src/assets/private/three.js:\n "
+ }
+ }
+ ]
+ }
+ ],
+ "results": [
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "e5aea7d033ad2f52b0c68a45048d8297e59597971eb74ca387ebdb598e9d2631c1de6945ffea9d9dc2fce6bb0f1e8f8e966061e685f3f72c40459c30f9fe7235_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "Gruntfile.js",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 53,
+ "endLine": 75,
+ "snippet": {
+ "text": " const buffer = fs.readFileSync('dist/' + file)"
+ },
+ "startColumn": 22,
+ "startLine": 75
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application dynamically constructs file or path information. If the path\ninformation comes from user-supplied input, it could be abused to read sensitive files,\naccess other users' data, or aid in exploitation to gain further system access.\n\nUser input should never be used in constructing paths or files for interacting\nwith the filesystem. This includes filenames supplied by user uploads or downloads.\nIf possible, consider hashing user input or using unique values and\nuse `path.normalize` to resolve and validate the path information\nprior to processing any file functionality.\n\nExample using `path.normalize` and not allowing direct user input:\n```\n// User input, saved only as a reference\n// id is a randomly generated UUID to be used as the filename\nconst userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};\n// Restrict all file processing to this directory only\nconst basePath = '/app/restricted/';\n\n// Create the full path, but only use our random generated id as the filename\nconst joinedPath = path.join(basePath, userData.id);\n// Normalize path, removing any '..'\nconst fullPath = path.normalize(joinedPath);\n// Verify the fullPath is contained within our basePath\nif (!fullPath.startsWith(basePath)) {\n console.log(\"Invalid path specified!\");\n}\n// Process / work with file\n// ...\n```\n\nFor more information on path traversal issues see OWASP:\nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.pathtraversal.javascript_pathtraversal_rule-non-literal-fs-filename"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "9c296eada08658aade5cc1449646e28fe6fba56242c8365a94089385d17ebb9ebc57d023714020dafec0cc42e9f4b240a3b04f56f643f30bd2a83a43f1156137_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "cypress.config.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 15,
+ "endLine": 51,
+ "snippet": {
+ "text": " const trainingData = require(`data/chatbot/${utils.extractFilename(\n config.get('application.chatBot.trainingData')\n )}`)"
+ },
+ "startColumn": 32,
+ "startLine": 49
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application was found to dynamically import a module by calling `require` using a\nnon-literal string. An adversary might be able to read the first line of\narbitrary files. If they had write access to the file system, they may also be able to\nexecute arbitrary code.\n\nTo remediate this issue, use a hardcoded string literal when calling `require`. Never call it\nit with dynamically created variables or user-supplied data.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.require.javascript_require_rule-non-literal-require"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "0a4522949996c48f0c18478e4fc2a0f3e0194a199a99000ac5b1e63afd44c92e8040cf9d24657103334c7f4e683dd8e47aee1a21096310a2b49b5487af7cf294_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "data/datacreator.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 88,
+ "endLine": 226,
+ "snippet": {
+ "text": " for (let i = 0; i < length; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)) }"
+ },
+ "startColumn": 75,
+ "startLine": 226
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "0a4522949996c48f0c18478e4fc2a0f3e0194a199a99000ac5b1e63afd44c92e8040cf9d24657103334c7f4e683dd8e47aee1a21096310a2b49b5487af7cf294_1"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "data/datacreator.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 63,
+ "endLine": 244,
+ "snippet": {
+ "text": " quantity: product.quantity ?? Math.floor(Math.random() * 70 + 30),"
+ },
+ "startColumn": 50,
+ "startLine": 244
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "0a4522949996c48f0c18478e4fc2a0f3e0194a199a99000ac5b1e63afd44c92e8040cf9d24657103334c7f4e683dd8e47aee1a21096310a2b49b5487af7cf294_2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "data/datacreator.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 62,
+ "endLine": 292,
+ "snippet": {
+ "text": " product.price = product.price ?? Math.floor(Math.random() * 9 + 1)"
+ },
+ "startColumn": 49,
+ "startLine": 292
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "0a4522949996c48f0c18478e4fc2a0f3e0194a199a99000ac5b1e63afd44c92e8040cf9d24657103334c7f4e683dd8e47aee1a21096310a2b49b5487af7cf294_3"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "data/datacreator.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 37,
+ "endLine": 670,
+ "snippet": {
+ "text": " eta: Math.floor((Math.random() * 5) + 1).toString(),"
+ },
+ "startColumn": 24,
+ "startLine": 670
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "1765412c1862ca9f02046d6990deaae4daa0ca21684749623e0fc1435909766f5290f8e911b65d78fee540443d76d2793fa2df8a76e20d639b34ba79c0ca762c_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "frontend/src/app/change-password/change-password.component.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 6,
+ "endLine": 82,
+ "snippet": {
+ "text": " if (password !== passwordRepeat) {\n return { notSame: true }\n }"
+ },
+ "startColumn": 5,
+ "startLine": 80
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application was found executing string comparisons using one of `===`, `!==`, `==` or `!=`\nagainst security sensitive values. String comparisons like this are not constant time, meaning\nthe\nfirst character found not to match in the two strings will immediately exit the conditional\nstatement.\nThis allows an adversary to calculate or observe small timing differences depending on the\nstrings\npassed to this comparison. This potentially allows an adversary the ability to brute force a\nstring\nthat will match the expected value by monitoring different character values.\n\nTo remediate this issue, use the `crypto.timingSafeEqual` method when comparing strings.\n\nExample using `crypto.timingSafeEqual` to safely compare strings:\n```\nfunction constantTimeIsPasswordEqual(userInput) {\n // Retrieve the password from a secure data store such as a KMS or Hashicorp's vault.\n const password = getPasswordFromSecureDataStore();\n // Use crypto timingSafeEqual to ensure the comparison is done in constant time.\n return crypto.timingSafeEqual(Buffer.from(userInput, 'utf-8'), Buffer.from(password,\n'utf-8'));\n}\n```\n\nFor more information on constant time comparison see:\n- https://nodejs.org/api/crypto.html#crypto_crypto_timingsafeequal_a_b\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.timing.javascript_timing_rule-possible-timing-attacks"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "e096e0932f1c5e7d04dfdf6f195cfff703dfd8430ee0e2d464939878c19147773745841bdc59edaebcfcba422e5ed71c1b3e9545c2fb5d7002d11bc738279b0b_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "frontend/src/app/change-password/change-password.component.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 6,
+ "endLine": 82,
+ "snippet": {
+ "text": " if (password !== passwordRepeat) {\n return { notSame: true }\n }"
+ },
+ "startColumn": 5,
+ "startLine": 80
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "'String comparisons using ''==='', ''!=='', ''!='' and ''=='' is vulnerable to timing attacks. More info: https://snyk.io/blog/node-js-timing-attack-ccc-ctf/'\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-timing-attack"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "56eef4b45d46d52f6f853760c20f48e6060b6b1ced9678ff06cb1e56e9acbba79660bd9aef14f0c4d6549fdd2dfc1b2fe755679deb82605316bf5ec19d3d5316_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "frontend/src/app/code-snippet/code-snippet.component.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 62,
+ "endLine": 146,
+ "snippet": {
+ "text": " .map((fix, index) => ({ fix, index, sort: Math.random() }))"
+ },
+ "startColumn": 49,
+ "startLine": 146
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "fbb9370d26764a1dca1668340b6f5f4041e9129cde264eaf3448ccb50643f2976e88e4d522135f660afcd319d0af55ed3341c9fb9b797cc9fccdf5a175f36385_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "frontend/src/app/forgot-password/forgot-password.component.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 6,
+ "endLine": 120,
+ "snippet": {
+ "text": " if (password !== passwordRepeat) {\n return { notSame: true }\n }"
+ },
+ "startColumn": 5,
+ "startLine": 118
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application was found executing string comparisons using one of `===`, `!==`, `==` or `!=`\nagainst security sensitive values. String comparisons like this are not constant time, meaning\nthe\nfirst character found not to match in the two strings will immediately exit the conditional\nstatement.\nThis allows an adversary to calculate or observe small timing differences depending on the\nstrings\npassed to this comparison. This potentially allows an adversary the ability to brute force a\nstring\nthat will match the expected value by monitoring different character values.\n\nTo remediate this issue, use the `crypto.timingSafeEqual` method when comparing strings.\n\nExample using `crypto.timingSafeEqual` to safely compare strings:\n```\nfunction constantTimeIsPasswordEqual(userInput) {\n // Retrieve the password from a secure data store such as a KMS or Hashicorp's vault.\n const password = getPasswordFromSecureDataStore();\n // Use crypto timingSafeEqual to ensure the comparison is done in constant time.\n return crypto.timingSafeEqual(Buffer.from(userInput, 'utf-8'), Buffer.from(password,\n'utf-8'));\n}\n```\n\nFor more information on constant time comparison see:\n- https://nodejs.org/api/crypto.html#crypto_crypto_timingsafeequal_a_b\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.timing.javascript_timing_rule-possible-timing-attacks"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "884cba88bf3901a6da779ad33ad821c6de2abef6bd43d317b6006052864425ceea81fffb3f519784ca05bfb727e18fed69e884530d0343b53814887cfdcef0f7_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "frontend/src/app/forgot-password/forgot-password.component.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 6,
+ "endLine": 120,
+ "snippet": {
+ "text": " if (password !== passwordRepeat) {\n return { notSame: true }\n }"
+ },
+ "startColumn": 5,
+ "startLine": 118
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "'String comparisons using ''==='', ''!=='', ''!='' and ''=='' is vulnerable to timing attacks. More info: https://snyk.io/blog/node-js-timing-attack-ccc-ctf/'\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-timing-attack"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "b4435baefd52d010dff02fe462b3ba45adfbec072f397dde3be250a334660b80aefcfe8b4fdd1b6df00a74396774c3e7326edd41448011fbcab0dca9b943d9a8_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "frontend/src/app/register/register.component.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 6,
+ "endLine": 95,
+ "snippet": {
+ "text": " if (password !== passwordRepeat) {\n return { notSame: true }\n }"
+ },
+ "startColumn": 5,
+ "startLine": 93
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application was found executing string comparisons using one of `===`, `!==`, `==` or `!=`\nagainst security sensitive values. String comparisons like this are not constant time, meaning\nthe\nfirst character found not to match in the two strings will immediately exit the conditional\nstatement.\nThis allows an adversary to calculate or observe small timing differences depending on the\nstrings\npassed to this comparison. This potentially allows an adversary the ability to brute force a\nstring\nthat will match the expected value by monitoring different character values.\n\nTo remediate this issue, use the `crypto.timingSafeEqual` method when comparing strings.\n\nExample using `crypto.timingSafeEqual` to safely compare strings:\n```\nfunction constantTimeIsPasswordEqual(userInput) {\n // Retrieve the password from a secure data store such as a KMS or Hashicorp's vault.\n const password = getPasswordFromSecureDataStore();\n // Use crypto timingSafeEqual to ensure the comparison is done in constant time.\n return crypto.timingSafeEqual(Buffer.from(userInput, 'utf-8'), Buffer.from(password,\n'utf-8'));\n}\n```\n\nFor more information on constant time comparison see:\n- https://nodejs.org/api/crypto.html#crypto_crypto_timingsafeequal_a_b\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.timing.javascript_timing_rule-possible-timing-attacks"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "c185076b70400d7c3e137f47b5426dead8df860163bdc5372d36d862ff29c17964aac1d2b2a882352a398512deb5afdf1d2a46e62468425c8735aaef67b42dff_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "frontend/src/app/register/register.component.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 6,
+ "endLine": 95,
+ "snippet": {
+ "text": " if (password !== passwordRepeat) {\n return { notSame: true }\n }"
+ },
+ "startColumn": 5,
+ "startLine": 93
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "'String comparisons using ''==='', ''!=='', ''!='' and ''=='' is vulnerable to timing attacks. More info: https://snyk.io/blog/node-js-timing-attack-ccc-ctf/'\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-timing-attack"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "de3801fd9bf32351fc6496fe6fcb8b6b94be4dcc5d177a79ce4147e4d548244c3ddac84fb9bba9e86b78e4b8322130775104de69d8a36302029a17b277b959c1_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "lib/codingChallenges.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 34,
+ "endLine": 21,
+ "snippet": {
+ "text": " if ((await fs.lstat(currPath)).isDirectory()) {"
+ },
+ "startColumn": 16,
+ "startLine": 21
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application dynamically constructs file or path information. If the path\ninformation comes from user-supplied input, it could be abused to read sensitive files,\naccess other users' data, or aid in exploitation to gain further system access.\n\nUser input should never be used in constructing paths or files for interacting\nwith the filesystem. This includes filenames supplied by user uploads or downloads.\nIf possible, consider hashing user input or using unique values and\nuse `path.normalize` to resolve and validate the path information\nprior to processing any file functionality.\n\nExample using `path.normalize` and not allowing direct user input:\n```\n// User input, saved only as a reference\n// id is a randomly generated UUID to be used as the filename\nconst userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};\n// Restrict all file processing to this directory only\nconst basePath = '/app/restricted/';\n\n// Create the full path, but only use our random generated id as the filename\nconst joinedPath = path.join(basePath, userData.id);\n// Normalize path, removing any '..'\nconst fullPath = path.normalize(joinedPath);\n// Verify the fullPath is contained within our basePath\nif (!fullPath.startsWith(basePath)) {\n console.log(\"Invalid path specified!\");\n}\n// Process / work with file\n// ...\n```\n\nFor more information on path traversal issues see OWASP:\nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.pathtraversal.javascript_pathtraversal_rule-non-literal-fs-filename"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "de3801fd9bf32351fc6496fe6fcb8b6b94be4dcc5d177a79ce4147e4d548244c3ddac84fb9bba9e86b78e4b8322130775104de69d8a36302029a17b277b959c1_1"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "lib/codingChallenges.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 47,
+ "endLine": 22,
+ "snippet": {
+ "text": " const files = await fs.readdir(currPath)"
+ },
+ "startColumn": 27,
+ "startLine": 22
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application dynamically constructs file or path information. If the path\ninformation comes from user-supplied input, it could be abused to read sensitive files,\naccess other users' data, or aid in exploitation to gain further system access.\n\nUser input should never be used in constructing paths or files for interacting\nwith the filesystem. This includes filenames supplied by user uploads or downloads.\nIf possible, consider hashing user input or using unique values and\nuse `path.normalize` to resolve and validate the path information\nprior to processing any file functionality.\n\nExample using `path.normalize` and not allowing direct user input:\n```\n// User input, saved only as a reference\n// id is a randomly generated UUID to be used as the filename\nconst userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};\n// Restrict all file processing to this directory only\nconst basePath = '/app/restricted/';\n\n// Create the full path, but only use our random generated id as the filename\nconst joinedPath = path.join(basePath, userData.id);\n// Normalize path, removing any '..'\nconst fullPath = path.normalize(joinedPath);\n// Verify the fullPath is contained within our basePath\nif (!fullPath.startsWith(basePath)) {\n console.log(\"Invalid path specified!\");\n}\n// Process / work with file\n// ...\n```\n\nFor more information on path traversal issues see OWASP:\nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.pathtraversal.javascript_pathtraversal_rule-non-literal-fs-filename"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "de3801fd9bf32351fc6496fe6fcb8b6b94be4dcc5d177a79ce4147e4d548244c3ddac84fb9bba9e86b78e4b8322130775104de69d8a36302029a17b277b959c1_2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "lib/codingChallenges.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 57,
+ "endLine": 29,
+ "snippet": {
+ "text": " const code = await fs.readFile(currPath, 'utf8')"
+ },
+ "startColumn": 28,
+ "startLine": 29
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application dynamically constructs file or path information. If the path\ninformation comes from user-supplied input, it could be abused to read sensitive files,\naccess other users' data, or aid in exploitation to gain further system access.\n\nUser input should never be used in constructing paths or files for interacting\nwith the filesystem. This includes filenames supplied by user uploads or downloads.\nIf possible, consider hashing user input or using unique values and\nuse `path.normalize` to resolve and validate the path information\nprior to processing any file functionality.\n\nExample using `path.normalize` and not allowing direct user input:\n```\n// User input, saved only as a reference\n// id is a randomly generated UUID to be used as the filename\nconst userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};\n// Restrict all file processing to this directory only\nconst basePath = '/app/restricted/';\n\n// Create the full path, but only use our random generated id as the filename\nconst joinedPath = path.join(basePath, userData.id);\n// Normalize path, removing any '..'\nconst fullPath = path.normalize(joinedPath);\n// Verify the fullPath is contained within our basePath\nif (!fullPath.startsWith(basePath)) {\n console.log(\"Invalid path specified!\");\n}\n// Process / work with file\n// ...\n```\n\nFor more information on path traversal issues see OWASP:\nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.pathtraversal.javascript_pathtraversal_rule-non-literal-fs-filename"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "1cc123de3786726921d0576c8518e28b035b579a2caef34534fad4e20535c152a93f50cd8daddca4529c55ff4aacba58b46bdba249734f8f7d3722446eddc6b4_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "lib/codingChallenges.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 67,
+ "endLine": 76,
+ "snippet": {
+ "text": " if (new RegExp(`vuln-code-snippet vuln-line.*${challengeKey}`).exec(lines[i]) != null) {"
+ },
+ "startColumn": 9,
+ "startLine": 76
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The `RegExp` constructor was called with a non-literal value. If an adversary were able to\nsupply a malicious regex, they could cause a Regular Expression Denial of Service (ReDoS)\nagainst the application. In Node applications, this could cause the entire application to no\nlonger\nbe responsive to other users' requests.\n\nTo remediate this issue, never allow user-supplied regular expressions. Instead, the regular\nexpression should be\nhardcoded. If this is not possible, consider using an alternative regular expression engine\nsuch as [node-re2](https://www.npmjs.com/package/re2). RE2 is a safe alternative that does not\nsupport backtracking, which is what leads to ReDoS.\n\nExample using re2 which does not support backtracking (Note: it is still recommended to\nnever use user-supplied input):\n```\n// Import the re2 module\nconst RE2 = require('re2');\n\nfunction match(userSuppliedRegex, userInput) {\n // Create a RE2 object with the user supplied regex, this is relatively safe\n // due to RE2 not supporting backtracking which can be abused to cause long running\n // queries\n var re = new RE2(userSuppliedRegex);\n // Execute the regular expression against some userInput\n var result = re.exec(userInput);\n // Work with the result\n}\n```\n\nFor more information on Regular Expression DoS see:\n- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.dos.javascript_dos_rule-non-literal-regexp"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "1cc123de3786726921d0576c8518e28b035b579a2caef34534fad4e20535c152a93f50cd8daddca4529c55ff4aacba58b46bdba249734f8f7d3722446eddc6b4_1"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "lib/codingChallenges.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 77,
+ "endLine": 78,
+ "snippet": {
+ "text": " } else if (new RegExp(`vuln-code-snippet neutral-line.*${challengeKey}`).exec(lines[i]) != null) {"
+ },
+ "startColumn": 16,
+ "startLine": 78
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The `RegExp` constructor was called with a non-literal value. If an adversary were able to\nsupply a malicious regex, they could cause a Regular Expression Denial of Service (ReDoS)\nagainst the application. In Node applications, this could cause the entire application to no\nlonger\nbe responsive to other users' requests.\n\nTo remediate this issue, never allow user-supplied regular expressions. Instead, the regular\nexpression should be\nhardcoded. If this is not possible, consider using an alternative regular expression engine\nsuch as [node-re2](https://www.npmjs.com/package/re2). RE2 is a safe alternative that does not\nsupport backtracking, which is what leads to ReDoS.\n\nExample using re2 which does not support backtracking (Note: it is still recommended to\nnever use user-supplied input):\n```\n// Import the re2 module\nconst RE2 = require('re2');\n\nfunction match(userSuppliedRegex, userInput) {\n // Create a RE2 object with the user supplied regex, this is relatively safe\n // due to RE2 not supporting backtracking which can be abused to cause long running\n // queries\n var re = new RE2(userSuppliedRegex);\n // Execute the regular expression against some userInput\n var result = re.exec(userInput);\n // Work with the result\n}\n```\n\nFor more information on Regular Expression DoS see:\n- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.dos.javascript_dos_rule-non-literal-regexp"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "818741bfab9c8eeda854b5aef0ed42a69c6c8162cacd73900f17e650c20cfc099fa09e269c1f837ad572f858e3f9cd617583b1094ad50c7ddb0032935d36e81e_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "lib/insecurity.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 69,
+ "endLine": 55,
+ "snippet": {
+ "text": "export const denyAll = () => expressJwt({ secret: '' + Math.random() } as any)"
+ },
+ "startColumn": 56,
+ "startLine": 55
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "4a3e2ee59c608b0ad2e3ad574212e0b0ab7389f85eb224d1f99a6b1293502a57fecfc5ae3d123dcf44a478b361513002d7c033413f57da2b616614ece35fc48a_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "lib/insecurity.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 108,
+ "endLine": 56,
+ "snippet": {
+ "text": "export const authorize = (user = {}) => jwt.sign(user, privateKey, { expiresIn: '6h', algorithm: 'RS256' })"
+ },
+ "startColumn": 41,
+ "startLine": 56
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Hardcoded JWT secret or private key was found. Hardcoding secrets like JWT signing keys poses a significant security risk. \nIf the source code ends up in a public repository or is compromised, the secret is exposed. Attackers could then use the secret to \ngenerate forged tokens and access the system. Store it properly in an environment variable.\n\nHere are some recommended safe ways to access JWT secrets:\n - Use environment variables to store the secret and access it in code instead of hardcoding. This keeps it out of source control.\n - Use a secrets management service to securely store and tightly control access to the secret. Applications can request the secret at runtime.\n - For local development, use a .env file that is gitignored and access the secret from process.env.\n\nsample code snippet of accessing JWT secret from env variables\n```\n const token = jwt.sign(payload, process.env.SECRET, { algorithm: 'HS256' });\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.jwt.rules_lgpl_javascript_jwt_rule-hardcoded-jwt-secret"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "4bfbd82491bd2d6ac90203d82721c36f3c32cbc06d65bd346d3829156a409ab01f0ae2d1810fb7fdc1d183a2078ea8eabc794b695fa8d65f6a51ed07093b9e0a_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "lib/utils.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 33,
+ "endLine": 131,
+ "snippet": {
+ "text": " fs.writeFileSync(dest, data)"
+ },
+ "startColumn": 5,
+ "startLine": 131
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application dynamically constructs file or path information. If the path\ninformation comes from user-supplied input, it could be abused to read sensitive files,\naccess other users' data, or aid in exploitation to gain further system access.\n\nUser input should never be used in constructing paths or files for interacting\nwith the filesystem. This includes filenames supplied by user uploads or downloads.\nIf possible, consider hashing user input or using unique values and\nuse `path.normalize` to resolve and validate the path information\nprior to processing any file functionality.\n\nExample using `path.normalize` and not allowing direct user input:\n```\n// User input, saved only as a reference\n// id is a randomly generated UUID to be used as the filename\nconst userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};\n// Restrict all file processing to this directory only\nconst basePath = '/app/restricted/';\n\n// Create the full path, but only use our random generated id as the filename\nconst joinedPath = path.join(basePath, userData.id);\n// Normalize path, removing any '..'\nconst fullPath = path.normalize(joinedPath);\n// Verify the fullPath is contained within our basePath\nif (!fullPath.startsWith(basePath)) {\n console.log(\"Invalid path specified!\");\n}\n// Process / work with file\n// ...\n```\n\nFor more information on path traversal issues see OWASP:\nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.pathtraversal.javascript_pathtraversal_rule-non-literal-fs-filename"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "b791fb07e2b974ef6c94f59fcceb71ac7a979fd78002fe5989e865d07c6e072e3bd993c830fa00d80a426a9b8382ce8f4015ecefb1927667b662f1ed7919c767_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/address.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 106,
+ "endLine": 18,
+ "snippet": {
+ "text": " const address = await AddressModel.findOne({ where: { id: req.params.id, UserId: req.body.UserId } })"
+ },
+ "startColumn": 27,
+ "startLine": 18
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "31c96cc3cb626ceecfbe40724cc484f1e8d832a388a1b35daff4f23b00b15342f34d6679e21deef60875a31b3eb3a7ac088f3a6a9d7580f9c8fdb6f61a67498d_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/basket.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 9,
+ "endLine": 34,
+ "snippet": {
+ "text": " const id = req.params.id\n BasketModel.findOne({ where: { id }, include: [{ model: ProductModel, paranoid: false, as: 'Products' }] })\n .then((basket: BasketModel | null) => {\n /* jshint eqeqeq:false */\n challengeUtils.solveIf(challenges.basketAccessChallenge, () => {\n const user = security.authenticatedUsers.from(req)\n return user && id && id !== 'undefined' && id !== 'null' && id !== 'NaN' && user.bid && user.bid != id // eslint-disable-line eqeqeq\n })\n if (((basket?.Products) != null) && basket.Products.length > 0) {\n for (let i = 0; i < basket.Products.length; i++) {\n basket.Products[i].name = req.__(basket.Products[i].name)\n }\n }\n\n res.json(utils.queryResultToJson(basket))\n }).catch((error: Error) => {\n next(error)\n })"
+ },
+ "startColumn": 5,
+ "startLine": 17
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "2682647660a1d9685c23201ad66f51b3b2ef4827573b86d9df8475fef73edd5a38c4199f6e64520749513ea72cc5c59b787c690a093d812e795a920364dfc346_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/basket.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 112,
+ "endLine": 18,
+ "snippet": {
+ "text": " BasketModel.findOne({ where: { id }, include: [{ model: ProductModel, paranoid: false, as: 'Products' }] })"
+ },
+ "startColumn": 5,
+ "startLine": 18
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "8c7a6986a133b5746fd4b7a7c97d3d05cd33d468392b04bff6c1ecd4a232b8b64bd30cca1ce0a4bb18579efcad3260d578f0d339775df8d381ba71b81b1c5398_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/basketItems.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 62,
+ "endLine": 67,
+ "snippet": {
+ "text": " BasketItemModel.findOne({ where: { id: req.params.id } }).then((item: BasketItemModel | null) => {"
+ },
+ "startColumn": 5,
+ "startLine": 67
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "fcf9b6304878190f22b75d22e4a1c5039af584bbb46ca09909bfa49059460f6f86826943a76715be8542b1148bcc8c53460b5306c3d0cf5422eb40673976736b_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/captcha.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 48,
+ "endLine": 15,
+ "snippet": {
+ "text": " const firstTerm = Math.floor((Math.random() * 10) + 1)"
+ },
+ "startColumn": 35,
+ "startLine": 15
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "fcf9b6304878190f22b75d22e4a1c5039af584bbb46ca09909bfa49059460f6f86826943a76715be8542b1148bcc8c53460b5306c3d0cf5422eb40673976736b_1"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/captcha.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 49,
+ "endLine": 16,
+ "snippet": {
+ "text": " const secondTerm = Math.floor((Math.random() * 10) + 1)"
+ },
+ "startColumn": 36,
+ "startLine": 16
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "fcf9b6304878190f22b75d22e4a1c5039af584bbb46ca09909bfa49059460f6f86826943a76715be8542b1148bcc8c53460b5306c3d0cf5422eb40673976736b_2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/captcha.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 48,
+ "endLine": 17,
+ "snippet": {
+ "text": " const thirdTerm = Math.floor((Math.random() * 10) + 1)"
+ },
+ "startColumn": 35,
+ "startLine": 17
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "fcf9b6304878190f22b75d22e4a1c5039af584bbb46ca09909bfa49059460f6f86826943a76715be8542b1148bcc8c53460b5306c3d0cf5422eb40673976736b_3"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/captcha.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 62,
+ "endLine": 19,
+ "snippet": {
+ "text": " const firstOperator = operators[Math.floor((Math.random() * 3))]"
+ },
+ "startColumn": 49,
+ "startLine": 19
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "fcf9b6304878190f22b75d22e4a1c5039af584bbb46ca09909bfa49059460f6f86826943a76715be8542b1148bcc8c53460b5306c3d0cf5422eb40673976736b_4"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/captcha.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 63,
+ "endLine": 20,
+ "snippet": {
+ "text": " const secondOperator = operators[Math.floor((Math.random() * 3))]"
+ },
+ "startColumn": 50,
+ "startLine": 20
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This rule identifies use of cryptographically weak random number generators.\nUsing cryptographically weak random number generators like `crypto.pseudoRandomBytes()` \nand `Math.random()` for security-critical tasks can expose systems to significant \nvulnerabilities. Attackers might predict the generated random numbers, compromising \nthe integrity and confidentiality of cryptographic operations. This could lead to \nbreaches where sensitive data is accessed or manipulated, authentication mechanisms \nare bypassed, or secure communications are intercepted, ultimately undermining the \nsecurity of the entire system or application.\n\nMitigation strategy:\nReplace the use of these cryptographically weak random number generators with \n`crypto.randomBytes()`, a method provided by Node.js's `crypto` module that \ngenerates cryptographically secure random numbers. This method should be used \nfor all operations requiring secure randomness, such as generating keys, tokens, \nor any cryptographic material.\n\nSecure Code Example:\n```\nconst crypto = require('crypto');\nconst secureBytes = crypto.randomBytes(256);\nconsole.log(`Secure random bytes: ${secureBytes.toString('hex')}`);\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.crypto.rules_lgpl_javascript_crypto_rule-node-insecure-random-generator"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "939adb39bfd2a3c87450eaf233b0b71c388e8593018fdab9a87402768c22990224c48431aa99d090640c5ec42240433e2df30e99bf0667ccbe6e2aa62a6f7fee_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/captcha.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 36,
+ "endLine": 23,
+ "snippet": {
+ "text": " const answer = eval(expression).toString() // eslint-disable-line no-eval"
+ },
+ "startColumn": 20,
+ "startLine": 23
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application was found calling the `eval` function OR Function()\n constructor OR setTimeout() OR setInterval() methods. If the\n\n variables or strings or functions passed to these methods contains user-supplied input, an adversary could attempt to execute arbitrary\n\n JavaScript\n\n code. This could lead to a full system compromise in Node applications or Cross-site Scripting\n\n (XSS) in web applications.\n\n\n To remediate this issue, remove all calls to above methods and consider alternative methods for\n\n executing\n\n the necessary business logic. There is almost no safe method of calling `eval` or other above stated sinks with\n\n user-supplied input.\n\n Instead, consider alternative methods such as using property accessors to dynamically access\n\n values.\n\n\n Example using property accessors to dynamically access an object's property:\n\n ```\n\n // Define an object\n\n const obj = {key1: 'value1', key2: 'value2'};\n\n // Get key dynamically from user input\n\n const key = getUserInput();\n\n // Check if the key exists in our object and return it, or a default empty string\n\n const value = (obj.hasOwnProperty(key)) ? obj[key] : '';\n\n // Work with the value\n\n ```\n\n\n For more information on why not to use `eval`, and alternatives see:\n\n - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_eval!\n\n Other References:\n\n - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function\n\n - https://developer.mozilla.org/en-US/docs/Web/API/setTimeout\n\n - https://developer.mozilla.org/en-US/docs/Web/API/setInterval\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.eval.javascript_eval_rule-eval-with-expression"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "08489474d653ef8c076ed5dd681fdd109984639cd96a2eb121b2c0ef7297d20db85b85fe1d6b74dd4e91a5f1fe92e01ff4a02c5824a6c2f7c2ccf7e801c577a8_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/captcha.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 69,
+ "endLine": 37,
+ "snippet": {
+ "text": " CaptchaModel.findOne({ where: { captchaId: req.body.captchaId } }).then((captcha: Captcha | null) => {"
+ },
+ "startColumn": 3,
+ "startLine": 37
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "cee52f379850ab1d8d200cbb126ee255c3a94599b01f551cfee7130ee65b6a735b668264626eb3875ecb1a18ae107cef7185212a130fc4ecf8bb5b6ec5c82a5a_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/chatbot.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 53,
+ "endLine": 32,
+ "snippet": {
+ "text": " await fs.writeFile('data/chatbot/' + file, data)"
+ },
+ "startColumn": 11,
+ "startLine": 32
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application dynamically constructs file or path information. If the path\ninformation comes from user-supplied input, it could be abused to read sensitive files,\naccess other users' data, or aid in exploitation to gain further system access.\n\nUser input should never be used in constructing paths or files for interacting\nwith the filesystem. This includes filenames supplied by user uploads or downloads.\nIf possible, consider hashing user input or using unique values and\nuse `path.normalize` to resolve and validate the path information\nprior to processing any file functionality.\n\nExample using `path.normalize` and not allowing direct user input:\n```\n// User input, saved only as a reference\n// id is a randomly generated UUID to be used as the filename\nconst userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};\n// Restrict all file processing to this directory only\nconst basePath = '/app/restricted/';\n\n// Create the full path, but only use our random generated id as the filename\nconst joinedPath = path.join(basePath, userData.id);\n// Normalize path, removing any '..'\nconst fullPath = path.normalize(joinedPath);\n// Verify the fullPath is contained within our basePath\nif (!fullPath.startsWith(basePath)) {\n console.log(\"Invalid path specified!\");\n}\n// Process / work with file\n// ...\n```\n\nFor more information on path traversal issues see OWASP:\nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.pathtraversal.javascript_pathtraversal_rule-non-literal-fs-filename"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "cee52f379850ab1d8d200cbb126ee255c3a94599b01f551cfee7130ee65b6a735b668264626eb3875ecb1a18ae107cef7185212a130fc4ecf8bb5b6ec5c82a5a_1"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/chatbot.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 80,
+ "endLine": 41,
+ "snippet": {
+ "text": " const trainingSet = await fs.readFile(`data/chatbot/${trainingFile}`, 'utf8')"
+ },
+ "startColumn": 29,
+ "startLine": 41
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application dynamically constructs file or path information. If the path\ninformation comes from user-supplied input, it could be abused to read sensitive files,\naccess other users' data, or aid in exploitation to gain further system access.\n\nUser input should never be used in constructing paths or files for interacting\nwith the filesystem. This includes filenames supplied by user uploads or downloads.\nIf possible, consider hashing user input or using unique values and\nuse `path.normalize` to resolve and validate the path information\nprior to processing any file functionality.\n\nExample using `path.normalize` and not allowing direct user input:\n```\n// User input, saved only as a reference\n// id is a randomly generated UUID to be used as the filename\nconst userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};\n// Restrict all file processing to this directory only\nconst basePath = '/app/restricted/';\n\n// Create the full path, but only use our random generated id as the filename\nconst joinedPath = path.join(basePath, userData.id);\n// Normalize path, removing any '..'\nconst fullPath = path.normalize(joinedPath);\n// Verify the fullPath is contained within our basePath\nif (!fullPath.startsWith(basePath)) {\n console.log(\"Invalid path specified!\");\n}\n// Process / work with file\n// ...\n```\n\nFor more information on path traversal issues see OWASP:\nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.pathtraversal.javascript_pathtraversal_rule-non-literal-fs-filename"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "1c93eb92f605b1fef46a4452c01dc7087b0bf262fdebbc76d87e8b20e2a9cbe6e121a40676a68012dbd52e517c8c5b11c152b7c910fd69a0245500d70efc3c06_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/dataErasure.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 4,
+ "endLine": 44,
+ "snippet": {
+ "text": " const email = loggedInUser.data.email\n\n try {\n const answer = await SecurityAnswerModel.findOne({\n include: [{\n model: UserModel,\n where: { email }\n }]\n })\n if (answer == null) {\n throw new Error('No answer found!')\n }\n const question = await SecurityQuestionModel.findByPk(answer.SecurityQuestionId)\n if (question == null) {\n throw new Error('No question found!')\n }\n\n res.render('dataErasureForm', { userEmail: email, securityQuestion: question.question })\n } catch (error) {\n next(error)\n }"
+ },
+ "startColumn": 3,
+ "startLine": 24
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "13fe38ac24c5a9eedabda08825283797fd6f4d56750a58b29dba2374afad50ed430633c0f55c5f57b2e33e895f3b405c20d149955ea5ff36c83adc94815f802f_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/dataErasure.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 7,
+ "endLine": 32,
+ "snippet": {
+ "text": " const answer = await SecurityAnswerModel.findOne({\n include: [{\n model: UserModel,\n where: { email }\n }]\n })"
+ },
+ "startColumn": 26,
+ "startLine": 27
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "976073c632cd8e955efd964e02163a735b01888957543fee3f78e78107e19422d45b3f2302cf087318b6a948e16a3c4d50e7beddeeba8f0419ded92d021a406a_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/dataErasure.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 11,
+ "endLine": 82,
+ "snippet": {
+ "text": " res.render('dataErasureResult', {\n ...req.body\n }, (error, html) => {\n if (!html || error) {\n next(new Error(error.message))\n } else {\n const sendlfrResponse: string = html.slice(0, 100) + '......'\n res.send(sendlfrResponse)\n challengeUtils.solveIf(challenges.lfrChallenge, () => { return true })\n }\n })"
+ },
+ "startColumn": 9,
+ "startLine": 72
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This application is using untrusted user input in express render() function.\nRendering templates with untrusted user input enables arbitrary file read \nvulnerabilities when using templating engines like Handlebars (hbs). \n\nAn attacker can craft malicious input that traverses the filesystem and exposes sensitive files. \nConsider sanitizing and validating all user input before passing it to render() to prevent arbitrary file reads. \n\nSample safe use of express.render function\n```\napp.get(\"/traversal/2\", async (req, res) => {\n var indexPath = \"index\";\n res.render(indexPath, { title: \"Index Page\" })\n});\n```\n\nFor more details see: \nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.traversal.rules_lgpl_javascript_traversal_rule-express-lfr"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "fab68edf4ca86a86e300bd0292f22866033935ba5e4673f1aa3b3484d54ab1edc4ccbcadab03fd63dc54589f7474e8f1a63f3435d97aa8f72456e77e882866fb_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/dataErasure.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 9,
+ "endLine": 89,
+ "snippet": {
+ "text": " res.render('dataErasureResult', {\n ...req.body\n })"
+ },
+ "startColumn": 7,
+ "startLine": 87
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This application is using untrusted user input in express render() function.\nRendering templates with untrusted user input enables arbitrary file read \nvulnerabilities when using templating engines like Handlebars (hbs). \n\nAn attacker can craft malicious input that traverses the filesystem and exposes sensitive files. \nConsider sanitizing and validating all user input before passing it to render() to prevent arbitrary file reads. \n\nSample safe use of express.render function\n```\napp.get(\"/traversal/2\", async (req, res) => {\n var indexPath = \"index\";\n res.render(indexPath, { title: \"Index Page\" })\n});\n```\n\nFor more details see: \nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.traversal.rules_lgpl_javascript_traversal_rule-express-lfr"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "43d4d19b0eaf9ecc470e8ec503f45922845e090deb9e60d41c20ce0d12ad062d6b5a667cc337bab1442b57f82924d802195052e913ae12f57bc2c9d073f90c48_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/dataExport.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 149,
+ "endLine": 102,
+ "snippet": {
+ "text": " res.status(200).send({ userData: JSON.stringify(userData, null, 2), confirmation: 'Your data export will open in a new Browser window.' })"
+ },
+ "startColumn": 11,
+ "startLine": 102
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This application accepts user input directly from the client side without validation. This could lead to Cross Site Scripting (XSS) if the input contains malicious script code and the application server does not properly escape or sanitize the output. Consider encoding input data before sending it to the client side. \n``` // safe method of sending user input data router.get('/safe/1', (req, res) => {\n var name = encodeURI(req.query.name); \n res.send(name);\n}) ```\nXSS is an attack that exploits a web application or system to treat user input as markup or script code. It is important to encode the data depending on the specific context in which it is used. \n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.xss.rules_lgpl_javascript_xss_rule-express-xss"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "57605435232a50e72ed1e23d04b6fe44559daf1f24ee4b5f0d48ad6e31c7cd19e6ca88bc9c454731dd08d67e5540994c6eeaf00ef0ccb67a6134f5fd6e3ec695_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/delivery.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 81,
+ "endLine": 34,
+ "snippet": {
+ "text": " const method = await DeliveryModel.findOne({ where: { id: req.params.id } })"
+ },
+ "startColumn": 26,
+ "startLine": 34
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "2480c83b6ae9dd9bf57ff5a7aed77d42e0cad6a4ddbe19e3919e95df9bfe39c18bf5b6b99351127cd013ac87ce12ba650f60e3c6e6d8cdd5449eafd6fc010871_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/deluxe.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 110,
+ "endLine": 19,
+ "snippet": {
+ "text": " const user = await UserModel.findOne({ where: { id: req.body.UserId, role: security.roles.customer } })"
+ },
+ "startColumn": 26,
+ "startLine": 19
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "f88bfeb13641fb30960abe4d8bee79de328bd0c1b85aed34dc79cb0dcfb28cb2ba1646c1e1aaf73a4130db5111868248d3f57e5079c036e2dd53b5b098a3668f_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/deluxe.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 89,
+ "endLine": 25,
+ "snippet": {
+ "text": " const wallet = await WalletModel.findOne({ where: { UserId: req.body.UserId } })"
+ },
+ "startColumn": 30,
+ "startLine": 25
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "e8a73c05af7b895cd35c6c7b9e9c7479154c8fdb53893062a15f2662f8f049efb2920eb6b085401db6052eeac7ebaf5c52ba80d11e7ac25f47cceabe0593ebef_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/deluxe.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 109,
+ "endLine": 35,
+ "snippet": {
+ "text": " const card = await CardModel.findOne({ where: { id: req.body.paymentId, UserId: req.body.UserId } })"
+ },
+ "startColumn": 28,
+ "startLine": 35
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "19d434a3a0f3bff7232d4e3284fe3e15d2ed6595bd3c309dabd86eef361d4061e6503b35f8e2c25045955aa14674e6a00f27667339f7aa0492812a112a85e6c6_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/likeProductReviews.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 7,
+ "endLine": 63,
+ "snippet": {
+ "text": " const id = req.body.id\n const user = security.authenticatedUsers.from(req)\n db.reviews.findOne({ _id: id }).then((review: Review) => {\n if (!review) {\n res.status(404).json({ error: 'Not found' })\n } else {\n const likedBy = review.likedBy\n if (!likedBy.includes(user.data.email)) {\n db.reviews.update(\n { _id: id },\n { $inc: { likesCount: 1 } }\n ).then(\n () => {\n // Artificial wait for timing attack challenge\n setTimeout(function () {\n db.reviews.findOne({ _id: id }).then((review: Review) => {\n const likedBy = review.likedBy\n likedBy.push(user.data.email)\n let count = 0\n for (let i = 0; i < likedBy.length; i++) {\n if (likedBy[i] === user.data.email) {\n count++\n }\n }\n challengeUtils.solveIf(challenges.timingAttackChallenge, () => { return count > 2 })\n db.reviews.update(\n { _id: id },\n { $set: { likedBy } }\n ).then(\n (result: any) => {\n res.json(result)\n }, (err: unknown) => {\n res.status(500).json(err)\n })\n }, () => {\n res.status(400).json({ error: 'Wrong Params' })\n })\n }, 150)\n }, (err: unknown) => {\n res.status(500).json(err)\n })\n } else {\n res.status(403).json({ error: 'Not allowed' })\n }\n }\n }, () => {\n res.status(400).json({ error: 'Wrong Params' })\n })"
+ },
+ "startColumn": 5,
+ "startLine": 16
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "41adfa73d884d91ab7d8a5783bf62775e843becee5b3c227f222c82527ae592feda92c7e5da39bfe4c081a9117c888bde01586b17236d9f817b680e04fb9d488_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/order.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 9,
+ "endLine": 175,
+ "snippet": {
+ "text": " const id = req.params.id\n BasketModel.findOne({ where: { id }, include: [{ model: ProductModel, paranoid: false, as: 'Products' }] })\n .then(async (basket: BasketModel | null) => {\n if (basket != null) {\n const customer = security.authenticatedUsers.from(req)\n const email = customer ? customer.data ? customer.data.email : '' : ''\n const orderId = security.hash(email).slice(0, 4) + '-' + utils.randomHexString(16)\n const pdfFile = `order_${orderId}.pdf`\n const doc = new PDFDocument()\n const date = new Date().toJSON().slice(0, 10)\n const fileWriter = doc.pipe(fs.createWriteStream(path.join('ftp/', pdfFile)))\n\n fileWriter.on('finish', async () => {\n void basket.update({ coupon: null })\n await BasketItemModel.destroy({ where: { BasketId: id } })\n res.json({ orderConfirmation: orderId })\n })\n\n doc.font('Times-Roman', 40).text(config.get('application.name'), { align: 'center' })\n doc.moveTo(70, 115).lineTo(540, 115).stroke()\n doc.moveTo(70, 120).lineTo(540, 120).stroke()\n doc.fontSize(20).moveDown()\n doc.font('Times-Roman', 20).text(req.__('Order Confirmation'), { align: 'center' })\n doc.fontSize(20).moveDown()\n doc.font('Times-Roman', 15).text(`${req.__('Customer')}: ${email}`, { align: 'left' })\n doc.font('Times-Roman', 15).text(`${req.__('Order')} #: ${orderId}`, { align: 'left' })\n doc.moveDown()\n doc.font('Times-Roman', 15).text(`${req.__('Date')}: ${date}`, { align: 'left' })\n doc.moveDown()\n doc.moveDown()\n let totalPrice = 0\n const basketProducts: Product[] = []\n let totalPoints = 0\n basket.Products?.forEach(({ BasketItem, price, deluxePrice, name, id }) => {\n if (BasketItem != null) {\n challengeUtils.solveIf(challenges.christmasSpecialChallenge, () => { return BasketItem.ProductId === products.christmasSpecial.id })\n QuantityModel.findOne({ where: { ProductId: BasketItem.ProductId } }).then((product: any) => {\n const newQuantity = product.quantity - BasketItem.quantity\n QuantityModel.update({ quantity: newQuantity }, { where: { ProductId: BasketItem?.ProductId } }).catch((error: unknown) => {\n next(error)\n })\n }).catch((error: unknown) => {\n next(error)\n })\n let itemPrice: number\n if (security.isDeluxe(req)) {\n itemPrice = deluxePrice\n } else {\n itemPrice = price\n }\n const itemTotal = itemPrice * BasketItem.quantity\n const itemBonus = Math.round(itemPrice / 10) * BasketItem.quantity\n const product = {\n quantity: BasketItem.quantity,\n id,\n name: req.__(name),\n price: itemPrice,\n total: itemTotal,\n bonus: itemBonus\n }\n basketProducts.push(product)\n doc.text(`${BasketItem.quantity}x ${req.__(name)} ${req.__('ea.')} ${itemPrice} = ${itemTotal}\u00a4`)\n doc.moveDown()\n totalPrice += itemTotal\n totalPoints += itemBonus\n }\n })\n doc.moveDown()\n const discount = calculateApplicableDiscount(basket, req)\n let discountAmount = '0'\n if (discount > 0) {\n discountAmount = (totalPrice * (discount / 100)).toFixed(2)\n doc.text(discount + '% discount from coupon: -' + discountAmount + '\u00a4')\n doc.moveDown()\n totalPrice -= parseFloat(discountAmount)\n }\n const deliveryMethod = {\n deluxePrice: 0,\n price: 0,\n eta: 5\n }\n if (req.body.orderDetails?.deliveryMethodId) {\n const deliveryMethodFromModel = await DeliveryModel.findOne({ where: { id: req.body.orderDetails.deliveryMethodId } })\n if (deliveryMethodFromModel != null) {\n deliveryMethod.deluxePrice = deliveryMethodFromModel.deluxePrice\n deliveryMethod.price = deliveryMethodFromModel.price\n deliveryMethod.eta = deliveryMethodFromModel.eta\n }\n }\n const deliveryAmount = security.isDeluxe(req) ? deliveryMethod.deluxePrice : deliveryMethod.price\n totalPrice += deliveryAmount\n doc.text(`${req.__('Delivery Price')}: ${deliveryAmount.toFixed(2)}\u00a4`)\n doc.moveDown()\n doc.font('Helvetica-Bold', 20).text(`${req.__('Total Price')}: ${totalPrice.toFixed(2)}\u00a4`)\n doc.moveDown()\n doc.font('Helvetica-Bold', 15).text(`${req.__('Bonus Points Earned')}: ${totalPoints}`)\n doc.font('Times-Roman', 15).text(`(${req.__('The bonus points from this order will be added 1:1 to your wallet \u00a4-fund for future purchases!')}`)\n doc.moveDown()\n doc.moveDown()\n doc.font('Times-Roman', 15).text(req.__('Thank you for your order!'))\n\n challengeUtils.solveIf(challenges.negativeOrderChallenge, () => { return totalPrice < 0 })\n\n if (req.body.UserId) {\n if (req.body.orderDetails && req.body.orderDetails.paymentId === 'wallet') {\n const wallet = await WalletModel.findOne({ where: { UserId: req.body.UserId } })\n if ((wallet != null) && wallet.balance >= totalPrice) {\n WalletModel.decrement({ balance: totalPrice }, { where: { UserId: req.body.UserId } }).catch((error: unknown) => {\n next(error)\n })\n } else {\n next(new Error('Insufficient wallet balance.'))\n }\n }\n WalletModel.increment({ balance: totalPoints }, { where: { UserId: req.body.UserId } }).catch((error: unknown) => {\n next(error)\n })\n }\n\n db.orders.insert({\n promotionalAmount: discountAmount,\n paymentId: req.body.orderDetails ? req.body.orderDetails.paymentId : null,\n addressId: req.body.orderDetails ? req.body.orderDetails.addressId : null,\n orderId,\n delivered: false,\n email: (email ? email.replace(/[aeiou]/gi, '*') : undefined),\n totalPrice,\n products: basketProducts,\n bonus: totalPoints,\n deliveryPrice: deliveryAmount,\n eta: deliveryMethod.eta.toString()\n }).then(() => {\n doc.end()\n })\n } else {\n next(new Error(`Basket with id=${id} does not exist.`))\n }\n }).catch((error: unknown) => {\n next(error)\n })"
+ },
+ "startColumn": 5,
+ "startLine": 36
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "14485090513e6bee20246f491666fc4a321a2fa3bf3e99d48291ad01bec404b35d4a2d353858c8c866d8108dfe2d70f982f0e8c8b8e4449a4a366170b5002612_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/order.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 112,
+ "endLine": 37,
+ "snippet": {
+ "text": " BasketModel.findOne({ where: { id }, include: [{ model: ProductModel, paranoid: false, as: 'Products' }] })"
+ },
+ "startColumn": 5,
+ "startLine": 37
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "805e14e66f67d3c6054df582c81346adc6064916179b615abe9a7b1c804477464e662b3abc3c08f799367092b68b0838ab61ba57fe8eb5a6bc3a4fc4a19b384c_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/order.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 87,
+ "endLine": 46,
+ "snippet": {
+ "text": " const fileWriter = doc.pipe(fs.createWriteStream(path.join('ftp/', pdfFile)))"
+ },
+ "startColumn": 39,
+ "startLine": 46
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "The application dynamically constructs file or path information. If the path\ninformation comes from user-supplied input, it could be abused to read sensitive files,\naccess other users' data, or aid in exploitation to gain further system access.\n\nUser input should never be used in constructing paths or files for interacting\nwith the filesystem. This includes filenames supplied by user uploads or downloads.\nIf possible, consider hashing user input or using unique values and\nuse `path.normalize` to resolve and validate the path information\nprior to processing any file functionality.\n\nExample using `path.normalize` and not allowing direct user input:\n```\n// User input, saved only as a reference\n// id is a randomly generated UUID to be used as the filename\nconst userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};\n// Restrict all file processing to this directory only\nconst basePath = '/app/restricted/';\n\n// Create the full path, but only use our random generated id as the filename\nconst joinedPath = path.join(basePath, userData.id);\n// Normalize path, removing any '..'\nconst fullPath = path.normalize(joinedPath);\n// Verify the fullPath is contained within our basePath\nif (!fullPath.startsWith(basePath)) {\n console.log(\"Invalid path specified!\");\n}\n// Process / work with file\n// ...\n```\n\nFor more information on path traversal issues see OWASP:\nhttps://owasp.org/www-community/attacks/Path_Traversal\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.javascript.pathtraversal.javascript_pathtraversal_rule-non-literal-fs-filename"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "99b0dd456fa747cb8b55a34952df8a2cb6c4cd5bfcf397d616ccf69bbe4459e2cd05ee1b9493132e3712b2ec293fb2bb86b0253f12c35b296df457b28386ab0f_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/order.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 84,
+ "endLine": 72,
+ "snippet": {
+ "text": " QuantityModel.findOne({ where: { ProductId: BasketItem.ProductId } }).then((product: any) => {"
+ },
+ "startColumn": 15,
+ "startLine": 72
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "73cc0599caead7be6aab868232bac92d489b1b951c966953bf6ddefe9d85b8287c048bbf525119c8b48af68c57b3f09ba98a9e07d2e61e3447c1aa05f62fc9d4_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/order.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 131,
+ "endLine": 118,
+ "snippet": {
+ "text": " const deliveryMethodFromModel = await DeliveryModel.findOne({ where: { id: req.body.orderDetails.deliveryMethodId } })"
+ },
+ "startColumn": 51,
+ "startLine": 118
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "82a8095551060a4fc013db9541772bf8c5955fdee5e9a8783bc60d6735d5a97143e9eaa16c666f18734ba428f33b954cd9195a57305fd73c0210b5247d8a1188_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/order.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 95,
+ "endLine": 141,
+ "snippet": {
+ "text": " const wallet = await WalletModel.findOne({ where: { UserId: req.body.UserId } })"
+ },
+ "startColumn": 36,
+ "startLine": 141
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "9fb9a9036a11f1093d8b884ec9cae44a25864b8f24068a09b807d1b3e5fde72d8bca6cdecce9aa7245f5ae346856daecbde81154815af18a8ea67702d7047965_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/payment.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 100,
+ "endLine": 41,
+ "snippet": {
+ "text": " const card = await CardModel.findOne({ where: { id: req.params.id, UserId: req.body.UserId } })"
+ },
+ "startColumn": 24,
+ "startLine": 41
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "d78bcdaba6881fb7a6d577de6022a7b63bf8ff5e3337bea6140c7bbf08e47294aa98ee57cacf4b123d3fbfe2af55521c9020458ecfa8c0ea5f8f469c01b4a2b9_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/profileImageFileUpload.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 15,
+ "endLine": 34,
+ "snippet": {
+ "text": " fs.write(fd, buffer, 0, buffer.length, null, function (err) {\n if (err != null) logger.warn('Error writing file: ' + err.message)\n fs.close(fd, function () { })\n })"
+ },
+ "startColumn": 13,
+ "startLine": 31
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "This application accepts user input directly from the client side without validation. This could lead to Cross Site Scripting (XSS) if the input contains malicious script code and the application server does not properly escape or sanitize the output. Consider encoding input data before sending it to the client side. \n``` // safe method of sending user input data router.get('/safe/1', (req, res) => {\n var name = encodeURI(req.query.name); \n res.send(name);\n}) ```\nXSS is an attack that exploits a web application or system to treat user input as markup or script code. It is important to encode the data depending on the specific context in which it is used. \n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.xss.rules_lgpl_javascript_xss_rule-express-xss"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "b9ecc75584aadb1a4d675d437b6a44d59cf0f6e536c8806e099fb1cd36d2414a6e594ad1de020434985978ec8a17cbca8a1d16ec05e0d8b2e2a0b7801955596b_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/profileImageUrlUpload.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 8,
+ "endLine": 37,
+ "snippet": {
+ "text": " const url = req.body.imageUrl\n if (url.match(/(.)*solve\\/challenges\\/server-side(.)*/) !== null) req.app.locals.abused_ssrf_bug = true\n const loggedInUser = security.authenticatedUsers.get(req.cookies.token)\n if (loggedInUser) {\n const imageRequest = request\n .get(url)\n .on('error', function (err: unknown) {\n UserModel.findByPk(loggedInUser.data.id).then(async (user: UserModel | null) => { return await user?.update({ profileImage: url }) }).catch((error: Error) => { next(error) })\n logger.warn(`Error retrieving user profile image: ${utils.getErrorMessage(err)}; using image link directly`)\n })\n .on('response', function (res: Response) {\n if (res.statusCode === 200) {\n const ext = ['jpg', 'jpeg', 'png', 'svg', 'gif'].includes(url.split('.').slice(-1)[0].toLowerCase()) ? url.split('.').slice(-1)[0].toLowerCase() : 'jpg'\n imageRequest.pipe(fs.createWriteStream(`frontend/dist/frontend/assets/public/images/uploads/${loggedInUser.data.id}.${ext}`))\n UserModel.findByPk(loggedInUser.data.id).then(async (user: UserModel | null) => { return await user?.update({ profileImage: `/assets/public/images/uploads/${loggedInUser.data.id}.${ext}` }) }).catch((error: Error) => { next(error) })\n } else UserModel.findByPk(loggedInUser.data.id).then(async (user: UserModel | null) => { return await user?.update({ profileImage: url }) }).catch((error: Error) => { next(error) })\n })\n } else {\n next(new Error('Blocked illegal activity by ' + req.socket.remoteAddress))\n }"
+ },
+ "startColumn": 7,
+ "startLine": 18
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "User controlled URL in http client libraries can result in Server Side Request Forgery (SSRF).\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.ssrf.rules_lgpl_javascript_ssrf_rule-node-ssrf"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "e3ae16b41a29c85d6cb2f62571598c33541615b44b98e601736a557bf819c1a6efa54e214f6d6c2fbac7023a28690d2197820afdf1c71028a47782c2c3ecc277_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/profileImageUrlUpload.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 78,
+ "endLine": 20,
+ "snippet": {
+ "text": " const loggedInUser = security.authenticatedUsers.get(req.cookies.token)"
+ },
+ "startColumn": 28,
+ "startLine": 20
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "User controlled URL in http client libraries can result in Server Side Request Forgery (SSRF).\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.ssrf.rules_lgpl_javascript_ssrf_rule-node-ssrf"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "aa19c74ebc9eeb9ed4967207fae4b2523c5f3a3ac9cc3b5df005a8cf1f0ba0d0023eb8df3410b6858ae5106ceff3009eb62164f2d583e584b59a2ad7ac25d206_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/recycles.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 35,
+ "endLine": 14,
+ "snippet": {
+ "text": " id: JSON.parse(req.params.id)"
+ },
+ "startColumn": 22,
+ "startLine": 14
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Passing untrusted user input in `xpath.parse()` can result in XPATH injection\nvulnerability. This could be abused by malicious actors to execute expressions on\non XML files to capture unauthorized information.\nTo prevent XPATH injection vulnerabilities:\n\n- Always validate and sanitize user inputs, especially parameters\nor query strings that may influence the flow of the application.\n- Avoid directly using user input for parsing. If unavoidable, ensure\nstrict validation against an allowlist. \n- Use allowlists (lists of permitted expressions) to validate user input \nagainst known, trusted expressions before performing the parse.\n\n\nFollowing is an example of secure validation against allowlist to prevent the vulnerability:\n```\n// Define a list of explicitly allowed expressions for parsing\nconst allowedExpr = [\n 'expression1',\n 'expression2',\n 'expression3'\n];\n\napp.get('/xml/xpath/1', (req, res) => {\n var expression = req.params.exp;\n var isAllowed = allowedExpr.includes(expression);\n let xml_string = fs.readFileSync(\"books.xml\", \"utf8\");\n var doc = new dom().parseFromString(xml_string, 'text/xml');\n if (isAllowed) {\n // If the expression is allowed, proceed with the parsing\n var evaluator = xpath.parse(\"//\"+expression);\n var nodes = evaluator.select({ node: doc }); \n res.send(nodes[0].firstChild.data);\n } else {\n res.status(400).send('Invalid expression');\n }\n});\n```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.xml.rules_lgpl_javascript_xml_rule-node-xpath-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "7d684be7ed2bac56b7f1bee11b3591ac24148257d872b1845a4201ea71fbc25c59d208b085b2a5c97b9d95d5d0ae38da11ce8c993823deffa95e609c9074459b_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/redirect.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 36,
+ "endLine": 19,
+ "snippet": {
+ "text": " res.redirect(toUrl as string)"
+ },
+ "startColumn": 7,
+ "startLine": 19
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Passing untrusted user input in `redirect()` can result in an open redirect\nvulnerability. This could be abused by malicious actors to trick users into \nbeing redirected to websites under their control to capture authentication\ninformation. \nTo prevent open redirect vulnerabilities:\n\n- Always validate and sanitize user inputs, especially URL parameters\n or query strings that may influence the flow of the application.\n- Use allowlists (lists of permitted URLs) to validate redirect targets \n against known, trusted URLs before performing the redirect.\n- Avoid directly using user input for redirecting. If unavoidable, ensure\n strict validation against an allowlist.\n\nFollowing is an example of secure validation against allowlist to prevent the vulnerability:\n ```\n // Define a list of explicitly allowed URLs for redirection\n const allowedUrls = [\n 'https://www.example.com/page1',\n 'https://www.example.com/page2',\n 'https://secure.example.com/page3'\n ];\n\n app.get('/redirect/:url', (req, res) => {\n const url = decodeURIComponent(req.params.url);\n const isAllowed = allowedUrls.includes(url);\n if (isAllowed) {\n // If the URL is allowed, proceed with the redirect\n res.redirect(url);\n } else {\n res.status(400).send('Invalid redirect URL');\n }\n });\n ```\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.redirect.rules_lgpl_javascript_redirect_rule-express-open-redirect"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "89e7e813b8f74d2653037d2c9d977b710a9330176ce5f94a17892794aaa0a2142e448d6d8983ec6f53d5897dd032f403dd34b7b1999cced95279a07bf9b9a02d_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/resetPassword.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 6,
+ "endLine": 53,
+ "snippet": {
+ "text": " const email = body.email\n const answer = body.answer\n const newPassword = body.new\n const repeatPassword = body.repeat\n if (!email || !answer) {\n next(new Error('Blocked illegal activity by ' + connection.remoteAddress))\n } else if (!newPassword || newPassword === 'undefined') {\n res.status(401).send(res.__('Password cannot be empty.'))\n } else if (newPassword !== repeatPassword) {\n res.status(401).send(res.__('New and repeated password do not match.'))\n } else {\n SecurityAnswerModel.findOne({\n include: [{\n model: UserModel,\n where: { email }\n }]\n }).then((data: SecurityAnswerModel | null) => {\n if ((data != null) && security.hmac(answer) === data.answer) {\n UserModel.findByPk(data.UserId).then((user: UserModel | null) => {\n user?.update({ password: newPassword }).then((user: UserModel) => {\n verifySecurityAnswerChallenges(user, answer)\n res.json({ user })\n }).catch((error: unknown) => {\n next(error)\n })\n }).catch((error: unknown) => {\n next(error)\n })\n } else {\n res.status(401).send(res.__('Wrong answer to security question.'))\n }\n }).catch((error: unknown) => {\n next(error)\n })\n }"
+ },
+ "startColumn": 5,
+ "startLine": 19
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "5be1bb2e6988fc9f6aa6aed4d619027e9b2dd774314b2298c483445a49c6c30c548ec8dd3114ce3cc27d0b6d0abda216655047b6974a9027d75d3d2137d939fb_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/resetPassword.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 9,
+ "endLine": 35,
+ "snippet": {
+ "text": " SecurityAnswerModel.findOne({\n include: [{\n model: UserModel,\n where: { email }\n }]\n }).then((data: SecurityAnswerModel | null) => {"
+ },
+ "startColumn": 7,
+ "startLine": 30
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "a217bbe3f490dc2ff12be90f894bc88bbddf7a4bd08c5127901792b1d613e0727121017c50a069f1e7b52b5e97a56b60757e5bc880d22df363a662bd0be67007_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/securityQuestion.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 7,
+ "endLine": 31,
+ "snippet": {
+ "text": " const email = query.email\n SecurityAnswerModel.findOne({\n include: [{\n model: UserModel,\n where: { email: email?.toString() }\n }]\n }).then((answer: SecurityAnswerModel | null) => {\n if (answer != null) {\n SecurityQuestionModel.findByPk(answer.SecurityQuestionId).then((question: SecurityQuestionModel | null) => {\n res.json({ question })\n }).catch((error: Error) => {\n next(error)\n })\n } else {\n res.json({})\n }\n }).catch((error: unknown) => {\n next(error)\n })"
+ },
+ "startColumn": 5,
+ "startLine": 13
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "2db8d7479e225f0e50d345453c77fd100d9d80540cf43d0ebdb860788ef08b5e8d87941c64e7273860d2f8cd6933efc5c652c02f72a37fb7b747c11bfa72f4c5_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/securityQuestion.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 7,
+ "endLine": 19,
+ "snippet": {
+ "text": " SecurityAnswerModel.findOne({\n include: [{\n model: UserModel,\n where: { email: email?.toString() }\n }]\n }).then((answer: SecurityAnswerModel | null) => {"
+ },
+ "startColumn": 5,
+ "startLine": 14
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in findOne() function can result in NoSQL Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "74e7d5b9c87465607833139f213989c7cfb3a0d310cf1b3a7eb425fc9ea335cc7dcb772e82b2d5af85217a0e8f7ef4a9e1e4d0545566b2a4ce9f2ff2bdb83015_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/showProductReviews.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 7,
+ "endLine": 46,
+ "snippet": {
+ "text": " const id = utils.disableOnContainerEnv() ? Number(req.params.id) : req.params.id\n\n // Measure how long the query takes, to check if there was a nosql dos attack\n const t0 = new Date().getTime()\n db.reviews.find({ $where: 'this.product == ' + id }).then((reviews: Review[]) => {\n const t1 = new Date().getTime()\n challengeUtils.solveIf(challenges.noSqlCommandChallenge, () => { return (t1 - t0) > 2000 })\n const user = security.authenticatedUsers.from(req)\n for (let i = 0; i < reviews.length; i++) {\n if (user === undefined || reviews[i].likedBy.includes(user.data.email)) {\n reviews[i].liked = true\n }\n }\n res.json(utils.queryResultToJson(reviews))\n }, () => {\n res.status(400).json({ error: 'Wrong Params' })\n })"
+ },
+ "startColumn": 5,
+ "startLine": 30
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": "Untrusted user input in MongoDB $where operator can result in NoSQL JavaScript Injection.\n"
+ },
+ "properties": {},
+ "ruleId": "vulnerability-management-registry.semgrep-rules.gitlab-rules.sast-rules.rules.lgpl.javascript.database.rules_lgpl_javascript_database_rule-node-nosqli-js-injection"
+ },
+ {
+ "fingerprints": {
+ "matchBasedId/v1": "fa3cc4d3dc4248909256e624a9dad80b1c448ab6a21c13f40133fa406212b88990f87f5277c8bea6c9471aec2b4e2d468e56af163ade09c6a1d7a4dbdd92691e_0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "routes/trackOrder.ts",
+ "uriBaseId": "%SRCROOT%"
+ },
+ "region": {
+ "endColumn": 7,
+ "endLine": 27,
+ "snippet": {
+ "text": " const id = utils.disableOnContainerEnv() ? String(req.params.id).replace(/[^\\w-]+/g, '') : req.params.id\n\n challengeUtils.solveIf(challenges.reflectedXssChallenge, () => { return utils.contains(id, '