From bc4e16897bb1a1b8351e820a7c580b42c3e3fd80 Mon Sep 17 00:00:00 2001 From: soonnae Date: Sun, 27 Jul 2025 02:08:51 +0900 Subject: [PATCH 1/2] [AutoFiC] Fix --- .../llm/response_core_appHandler.js.md | 281 ++++++++ .../downloaded_repo/llm/response_server.js.md | 70 ++ .../downloaded_repo/parsed/core/appHandler.js | 254 +++++++ artifacts/downloaded_repo/parsed/server.js | 49 ++ .../downloaded_repo/patch/appHandler.diff | 63 ++ artifacts/downloaded_repo/patch/server.diff | 22 + artifacts/downloaded_repo/repo | 1 + artifacts/downloaded_repo/sast/before.json | 620 ++++++++++++++++++ .../downloaded_repo/sast/merged_snippets.json | 52 ++ .../snippets/snippet_core_appHandler.js.json | 1 + .../snippets/snippet_server.js.json | 1 + sast/before.json | 1 + src/autofic_core/app.py | 149 +++-- src/autofic_core/patch/apply_patch.py | 6 +- src/autofic_core/pipeline.py | 31 +- src/autofic_core/pr_auto/create_yml.py | 10 +- src/autofic_core/pr_auto/env_encrypt.py | 38 +- src/autofic_core/pr_auto/pr_procedure.py | 14 +- src/autofic_core/utils/progress_utils.py | 14 +- src/autofic_core/utils/ui_utils.py | 22 +- 20 files changed, 1583 insertions(+), 116 deletions(-) create mode 100644 artifacts/downloaded_repo/llm/response_core_appHandler.js.md create mode 100644 artifacts/downloaded_repo/llm/response_server.js.md create mode 100644 artifacts/downloaded_repo/parsed/core/appHandler.js create mode 100644 artifacts/downloaded_repo/parsed/server.js create mode 100644 artifacts/downloaded_repo/patch/appHandler.diff create mode 100644 artifacts/downloaded_repo/patch/server.diff create mode 160000 artifacts/downloaded_repo/repo create mode 100644 artifacts/downloaded_repo/sast/before.json create mode 100644 artifacts/downloaded_repo/sast/merged_snippets.json create mode 100644 artifacts/downloaded_repo/snippets/snippet_core_appHandler.js.json create mode 100644 artifacts/downloaded_repo/snippets/snippet_server.js.json create mode 100644 sast/before.json diff --git a/artifacts/downloaded_repo/llm/response_core_appHandler.js.md b/artifacts/downloaded_repo/llm/response_core_appHandler.js.md new file mode 100644 index 0000000..5352d3b --- /dev/null +++ b/artifacts/downloaded_repo/llm/response_core_appHandler.js.md @@ -0,0 +1,281 @@ +1. 취약점 설명: + - SQL Injection: `userSearch` 함수에서 사용자 입력이 직접 SQL 쿼리에 포함되어 SQL 인젝션 공격에 취약합니다. + - Open Redirect: `redirect` 함수에서 사용자 입력을 통해 리다이렉트 URL이 결정되며, 이는 악의적인 사이트로의 리다이렉트에 악용될 수 있습니다. + - Insecure Deserialization: `bulkProductsLegacy` 함수에서 `serialize.unserialize`를 사용하여 사용자 입력을 역직렬화하고 있어 원격 코드 실행(RCE)에 취약합니다. + - XML Injection: `bulkProducts` 함수에서 `libxmljs`의 `noent` 옵션이 `true`로 설정되어 있어 XML 외부 엔티티(XXE) 공격에 취약합니다. + +2. 예상 위험: + - SQL Injection을 통해 데이터베이스가 손상되거나 민감한 정보가 유출될 수 있습니다. + - Open Redirect를 통해 사용자가 악의적인 사이트로 유도될 수 있습니다. + - Insecure Deserialization을 통해 원격 코드 실행이 발생할 수 있습니다. + - XML Injection을 통해 서버의 파일 시스템 접근 및 데이터 유출이 발생할 수 있습니다. + +3. 개선 방안: + - SQL Injection: 파라미터화된 쿼리를 사용하여 사용자 입력을 안전하게 처리합니다. + - Open Redirect: 허용된 URL 목록을 사용하여 리다이렉트 URL을 검증합니다. + - Insecure Deserialization: `serialize.unserialize` 대신 안전한 데이터 처리 방법을 사용합니다. + - XML Injection: `noent` 옵션을 `false`로 설정하여 XXE 공격을 방지합니다. + +4. 최종 수정된 전체 코드: +```javascript +var db = require('../models') +var bCrypt = require('bcrypt') +const exec = require('child_process').exec; +var mathjs = require('mathjs') +var libxmljs = require("libxmljs"); +var serialize = require("node-serialize") +const Op = db.Sequelize.Op + +module.exports.userSearch = function (req, res) { + var query = "SELECT name,id FROM Users WHERE login=:login"; + db.sequelize.query(query, { + replacements: { login: req.body.login }, + model: db.User + }).then(user => { + if (user.length) { + var output = { + user: { + name: user[0].name, + id: user[0].id + } + } + res.render('app/usersearch', { + output: output + }) + } else { + req.flash('warning', 'User not found') + res.render('app/usersearch', { + output: null + }) + } + }).catch(err => { + req.flash('danger', 'Internal Error') + res.render('app/usersearch', { + output: null + }) + }) +} + +module.exports.ping = function (req, res) { + exec('ping -c 2 ' + req.body.address, function (err, stdout, stderr) { + output = stdout + stderr + res.render('app/ping', { + output: output + }) + }) +} + +module.exports.listProducts = function (req, res) { + db.Product.findAll().then(products => { + output = { + products: products + } + res.render('app/products', { + output: output + }) + }) +} + +module.exports.productSearch = function (req, res) { + db.Product.findAll({ + where: { + name: { + [Op.like]: '%' + req.body.name + '%' + } + } + }).then(products => { + output = { + products: products, + searchTerm: req.body.name + } + res.render('app/products', { + output: output + }) + }) +} + +module.exports.modifyProduct = function (req, res) { + if (!req.query.id || req.query.id == '') { + output = { + product: {} + } + res.render('app/modifyproduct', { + output: output + }) + } else { + db.Product.find({ + where: { + 'id': req.query.id + } + }).then(product => { + if (!product) { + product = {} + } + output = { + product: product + } + res.render('app/modifyproduct', { + output: output + }) + }) + } +} + +module.exports.modifyProductSubmit = function (req, res) { + if (!req.body.id || req.body.id == '') { + req.body.id = 0 + } + db.Product.find({ + where: { + 'id': req.body.id + } + }).then(product => { + if (!product) { + product = new db.Product() + } + product.code = req.body.code + product.name = req.body.name + product.description = req.body.description + product.tags = req.body.tags + product.save().then(p => { + if (p) { + req.flash('success', 'Product added/modified!') + res.redirect('/app/products') + } + }).catch(err => { + output = { + product: product + } + req.flash('danger',err) + res.render('app/modifyproduct', { + output: output + }) + }) + }) +} + +module.exports.userEdit = function (req, res) { + res.render('app/useredit', { + userId: req.user.id, + userEmail: req.user.email, + userName: req.user.name + }) +} + +module.exports.userEditSubmit = function (req, res) { + db.User.find({ + where: { + 'id': req.body.id + } + }).then(user =>{ + if(req.body.password.length>0){ + if(req.body.password.length>0){ + if (req.body.password == req.body.cpassword) { + user.password = bCrypt.hashSync(req.body.password, bCrypt.genSaltSync(10), null) + }else{ + req.flash('warning', 'Passwords dont match') + res.render('app/useredit', { + userId: req.user.id, + userEmail: req.user.email, + userName: req.user.name, + }) + return + } + }else{ + req.flash('warning', 'Invalid Password') + res.render('app/useredit', { + userId: req.user.id, + userEmail: req.user.email, + userName: req.user.name, + }) + return + } + } + user.email = req.body.email + user.name = req.body.name + user.save().then(function () { + req.flash('success',"Updated successfully") + res.render('app/useredit', { + userId: req.body.id, + userEmail: req.body.email, + userName: req.body.name, + }) + }) + }) +} + +module.exports.redirect = function (req, res) { + const allowedUrls = ['https://trusted.com', 'https://another-trusted.com']; + if (req.query.url && allowedUrls.includes(req.query.url)) { + res.redirect(req.query.url) + } else { + res.send('invalid redirect url') + } +} + +module.exports.calc = function (req, res) { + if (req.body.eqn) { + res.render('app/calc', { + output: mathjs.eval(req.body.eqn) + }) + } else { + res.render('app/calc', { + output: 'Enter a valid math string like (3+3)*2' + }) + } +} + +module.exports.listUsersAPI = function (req, res) { + db.User.findAll({}).then(users => { + res.status(200).json({ + success: true, + users: users + }) + }) +} + +module.exports.bulkProductsLegacy = function (req,res){ + // TODO: Deprecate this soon + if(req.files.products){ + try { + var products = JSON.parse(req.files.products.data.toString('utf8')) + products.forEach( function (product) { + var newProduct = new db.Product() + newProduct.name = product.name + newProduct.code = product.code + newProduct.tags = product.tags + newProduct.description = product.description + newProduct.save() + }) + res.redirect('/app/products') + } catch (e) { + res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) + } + }else{ + res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) + } +} + +module.exports.bulkProducts = function(req, res) { + if (req.files.products && req.files.products.mimetype=='text/xml'){ + var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:false,noblanks:true}) + products.root().childNodes().forEach( product => { + var newProduct = new db.Product() + newProduct.name = product.childNodes()[0].text() + newProduct.code = product.childNodes()[1].text() + newProduct.tags = product.childNodes()[2].text() + newProduct.description = product.childNodes()[3].text() + newProduct.save() + }) + res.redirect('/app/products') + }else{ + res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:false}) + } +} +``` + +5. 참고사항: + - SQL Injection 방지를 위해 Sequelize의 `replacements` 옵션을 사용하여 파라미터화된 쿼리를 적용했습니다. + - Open Redirect 방지를 위해 허용된 URL 목록을 사용하여 검증을 추가했습니다. + - Insecure Deserialization 방지를 위해 `JSON.parse`를 사용하여 데이터를 안전하게 처리했습니다. + - XML Injection 방지를 위해 `libxmljs`의 `noent` 옵션을 `false`로 설정했습니다. \ No newline at end of file diff --git a/artifacts/downloaded_repo/llm/response_server.js.md b/artifacts/downloaded_repo/llm/response_server.js.md new file mode 100644 index 0000000..3b22516 --- /dev/null +++ b/artifacts/downloaded_repo/llm/response_server.js.md @@ -0,0 +1,70 @@ +1. 취약점 설명: + - 코드에서 세션 비밀 키가 하드코딩되어 있습니다. 이는 코드가 유출될 경우 비밀 키가 노출될 위험이 있습니다. + - 세션 설정에서 기본값을 사용하고 있으며, 이는 보안에 취약할 수 있습니다. 특히, `httpOnly`, `secure`, `domain`, `expires`, `path` 등의 속성이 설정되어 있지 않습니다. + +2. 예상 위험: + - 하드코딩된 비밀 키로 인해, 코드 유출 시 세션 탈취 등의 공격에 노출될 수 있습니다. + - 기본 세션 설정은 세션 하이재킹, XSS 공격 등에 취약할 수 있습니다. + +3. 개선 방안: + - 비밀 키는 환경 변수로 관리하여 코드에 직접 노출되지 않도록 합니다. + - 세션 설정에서 `httpOnly`, `secure`, `domain`, `expires`, `path` 등의 속성을 적절히 설정하여 보안을 강화합니다. + - 기본 세션 쿠키 이름을 변경하여 공격자가 서버를 식별하기 어렵게 합니다. + +4. 최종 수정된 전체 코드: +```javascript +var express = require('express') +var bodyParser = require('body-parser') +var passport = require('passport') +var session = require('express-session') +var ejs = require('ejs') +var morgan = require('morgan') +const fileUpload = require('express-fileupload'); +var config = require('./config/server') + +//Initialize Express +var app = express() +require('./core/passport')(passport) +app.use(express.static('public')) +app.set('view engine','ejs') +app.use(morgan('tiny')) +app.use(bodyParser.urlencoded({ extended: false })) +app.use(fileUpload()); + +// Enable for Reverse proxy support +// app.set('trust proxy', 1) + +// Intialize Session +app.use(session({ + secret: process.env.SESSION_SECRET || 'default_secret', + resave: true, + saveUninitialized: true, + name: 'session_id', + cookie: { + secure: process.env.NODE_ENV === 'production', + httpOnly: true, + domain: 'example.com', + expires: new Date(Date.now() + 60 * 60 * 1000), // 1 hour + path: '/' + } +})) + +// Initialize Passport +app.use(passport.initialize()) +app.use(passport.session()) + +// Initialize express-flash +app.use(require('express-flash')()); + +// Routing +app.use('/app',require('./routes/app')()) +app.use('/',require('./routes/main')(passport)) + +// Start Server +app.listen(config.port, config.listen) +``` + +5. 참고사항: + - `process.env.SESSION_SECRET` 환경 변수를 사용하여 비밀 키를 관리합니다. 환경 변수를 설정하지 않은 경우 `default_secret`을 사용하지만, 이는 개발 환경에서만 사용해야 합니다. + - `secure` 옵션은 `NODE_ENV`가 `production`일 때만 활성화되도록 설정하여, 개발 환경에서는 HTTPS가 필요하지 않도록 합니다. + - `domain` 및 `expires` 설정은 예시로 제공되었으며, 실제 환경에 맞게 조정해야 합니다. \ No newline at end of file diff --git a/artifacts/downloaded_repo/parsed/core/appHandler.js b/artifacts/downloaded_repo/parsed/core/appHandler.js new file mode 100644 index 0000000..482cde0 --- /dev/null +++ b/artifacts/downloaded_repo/parsed/core/appHandler.js @@ -0,0 +1,254 @@ +var db = require('../models') +var bCrypt = require('bcrypt') +const exec = require('child_process').exec; +var mathjs = require('mathjs') +var libxmljs = require("libxmljs"); +var serialize = require("node-serialize") +const Op = db.Sequelize.Op + +module.exports.userSearch = function (req, res) { + var query = "SELECT name,id FROM Users WHERE login=:login"; + db.sequelize.query(query, { + replacements: { login: req.body.login }, + model: db.User + }).then(user => { + if (user.length) { + var output = { + user: { + name: user[0].name, + id: user[0].id + } + } + res.render('app/usersearch', { + output: output + }) + } else { + req.flash('warning', 'User not found') + res.render('app/usersearch', { + output: null + }) + } + }).catch(err => { + req.flash('danger', 'Internal Error') + res.render('app/usersearch', { + output: null + }) + }) +} + +module.exports.ping = function (req, res) { + exec('ping -c 2 ' + req.body.address, function (err, stdout, stderr) { + output = stdout + stderr + res.render('app/ping', { + output: output + }) + }) +} + +module.exports.listProducts = function (req, res) { + db.Product.findAll().then(products => { + output = { + products: products + } + res.render('app/products', { + output: output + }) + }) +} + +module.exports.productSearch = function (req, res) { + db.Product.findAll({ + where: { + name: { + [Op.like]: '%' + req.body.name + '%' + } + } + }).then(products => { + output = { + products: products, + searchTerm: req.body.name + } + res.render('app/products', { + output: output + }) + }) +} + +module.exports.modifyProduct = function (req, res) { + if (!req.query.id || req.query.id == '') { + output = { + product: {} + } + res.render('app/modifyproduct', { + output: output + }) + } else { + db.Product.find({ + where: { + 'id': req.query.id + } + }).then(product => { + if (!product) { + product = {} + } + output = { + product: product + } + res.render('app/modifyproduct', { + output: output + }) + }) + } +} + +module.exports.modifyProductSubmit = function (req, res) { + if (!req.body.id || req.body.id == '') { + req.body.id = 0 + } + db.Product.find({ + where: { + 'id': req.body.id + } + }).then(product => { + if (!product) { + product = new db.Product() + } + product.code = req.body.code + product.name = req.body.name + product.description = req.body.description + product.tags = req.body.tags + product.save().then(p => { + if (p) { + req.flash('success', 'Product added/modified!') + res.redirect('/app/products') + } + }).catch(err => { + output = { + product: product + } + req.flash('danger',err) + res.render('app/modifyproduct', { + output: output + }) + }) + }) +} + +module.exports.userEdit = function (req, res) { + res.render('app/useredit', { + userId: req.user.id, + userEmail: req.user.email, + userName: req.user.name + }) +} + +module.exports.userEditSubmit = function (req, res) { + db.User.find({ + where: { + 'id': req.body.id + } + }).then(user =>{ + if(req.body.password.length>0){ + if(req.body.password.length>0){ + if (req.body.password == req.body.cpassword) { + user.password = bCrypt.hashSync(req.body.password, bCrypt.genSaltSync(10), null) + }else{ + req.flash('warning', 'Passwords dont match') + res.render('app/useredit', { + userId: req.user.id, + userEmail: req.user.email, + userName: req.user.name, + }) + return + } + }else{ + req.flash('warning', 'Invalid Password') + res.render('app/useredit', { + userId: req.user.id, + userEmail: req.user.email, + userName: req.user.name, + }) + return + } + } + user.email = req.body.email + user.name = req.body.name + user.save().then(function () { + req.flash('success',"Updated successfully") + res.render('app/useredit', { + userId: req.body.id, + userEmail: req.body.email, + userName: req.body.name, + }) + }) + }) +} + +module.exports.redirect = function (req, res) { + const allowedUrls = ['https://trusted.com', 'https://another-trusted.com']; + if (req.query.url && allowedUrls.includes(req.query.url)) { + res.redirect(req.query.url) + } else { + res.send('invalid redirect url') + } +} + +module.exports.calc = function (req, res) { + if (req.body.eqn) { + res.render('app/calc', { + output: mathjs.eval(req.body.eqn) + }) + } else { + res.render('app/calc', { + output: 'Enter a valid math string like (3+3)*2' + }) + } +} + +module.exports.listUsersAPI = function (req, res) { + db.User.findAll({}).then(users => { + res.status(200).json({ + success: true, + users: users + }) + }) +} + +module.exports.bulkProductsLegacy = function (req,res){ + // TODO: Deprecate this soon + if(req.files.products){ + try { + var products = JSON.parse(req.files.products.data.toString('utf8')) + products.forEach( function (product) { + var newProduct = new db.Product() + newProduct.name = product.name + newProduct.code = product.code + newProduct.tags = product.tags + newProduct.description = product.description + newProduct.save() + }) + res.redirect('/app/products') + } catch (e) { + res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) + } + }else{ + res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) + } +} + +module.exports.bulkProducts = function(req, res) { + if (req.files.products && req.files.products.mimetype=='text/xml'){ + var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:false,noblanks:true}) + products.root().childNodes().forEach( product => { + var newProduct = new db.Product() + newProduct.name = product.childNodes()[0].text() + newProduct.code = product.childNodes()[1].text() + newProduct.tags = product.childNodes()[2].text() + newProduct.description = product.childNodes()[3].text() + newProduct.save() + }) + res.redirect('/app/products') + }else{ + res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:false}) + } +} \ No newline at end of file diff --git a/artifacts/downloaded_repo/parsed/server.js b/artifacts/downloaded_repo/parsed/server.js new file mode 100644 index 0000000..0ad9f8a --- /dev/null +++ b/artifacts/downloaded_repo/parsed/server.js @@ -0,0 +1,49 @@ +var express = require('express') +var bodyParser = require('body-parser') +var passport = require('passport') +var session = require('express-session') +var ejs = require('ejs') +var morgan = require('morgan') +const fileUpload = require('express-fileupload'); +var config = require('./config/server') + +//Initialize Express +var app = express() +require('./core/passport')(passport) +app.use(express.static('public')) +app.set('view engine','ejs') +app.use(morgan('tiny')) +app.use(bodyParser.urlencoded({ extended: false })) +app.use(fileUpload()); + +// Enable for Reverse proxy support +// app.set('trust proxy', 1) + +// Intialize Session +app.use(session({ + secret: process.env.SESSION_SECRET || 'default_secret', + resave: true, + saveUninitialized: true, + name: 'session_id', + cookie: { + secure: process.env.NODE_ENV === 'production', + httpOnly: true, + domain: 'example.com', + expires: new Date(Date.now() + 60 * 60 * 1000), // 1 hour + path: '/' + } +})) + +// Initialize Passport +app.use(passport.initialize()) +app.use(passport.session()) + +// Initialize express-flash +app.use(require('express-flash')()); + +// Routing +app.use('/app',require('./routes/app')()) +app.use('/',require('./routes/main')(passport)) + +// Start Server +app.listen(config.port, config.listen) \ No newline at end of file diff --git a/artifacts/downloaded_repo/patch/appHandler.diff b/artifacts/downloaded_repo/patch/appHandler.diff new file mode 100644 index 0000000..3d6325a --- /dev/null +++ b/artifacts/downloaded_repo/patch/appHandler.diff @@ -0,0 +1,63 @@ +--- a/core/appHandler.js ++++ b/core/appHandler.js +@@ -7,8 +7,9 @@ + const Op = db.Sequelize.Op + + module.exports.userSearch = function (req, res) { +- var query = "SELECT name,id FROM Users WHERE login='" + req.body.login + "'"; ++ var query = "SELECT name,id FROM Users WHERE login=:login"; + db.sequelize.query(query, { ++ replacements: { login: req.body.login }, + model: db.User + }).then(user => { + if (user.length) { +@@ -184,7 +185,8 @@ + } + + module.exports.redirect = function (req, res) { +- if (req.query.url) { ++ const allowedUrls = ['https://trusted.com', 'https://another-trusted.com']; ++ if (req.query.url && allowedUrls.includes(req.query.url)) { + res.redirect(req.query.url) + } else { + res.send('invalid redirect url') +@@ -215,16 +217,20 @@ + module.exports.bulkProductsLegacy = function (req,res){ + // TODO: Deprecate this soon + if(req.files.products){ +- var products = serialize.unserialize(req.files.products.data.toString('utf8')) +- products.forEach( function (product) { +- var newProduct = new db.Product() +- newProduct.name = product.name +- newProduct.code = product.code +- newProduct.tags = product.tags +- newProduct.description = product.description +- newProduct.save() +- }) +- res.redirect('/app/products') ++ try { ++ var products = JSON.parse(req.files.products.data.toString('utf8')) ++ products.forEach( function (product) { ++ var newProduct = new db.Product() ++ newProduct.name = product.name ++ newProduct.code = product.code ++ newProduct.tags = product.tags ++ newProduct.description = product.description ++ newProduct.save() ++ }) ++ res.redirect('/app/products') ++ } catch (e) { ++ res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) ++ } + }else{ + res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) + } +@@ -232,7 +238,7 @@ + + module.exports.bulkProducts = function(req, res) { + if (req.files.products && req.files.products.mimetype=='text/xml'){ +- var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true}) ++ var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:false,noblanks:true}) + products.root().childNodes().forEach( product => { + var newProduct = new db.Product() + newProduct.name = product.childNodes()[0].text() diff --git a/artifacts/downloaded_repo/patch/server.diff b/artifacts/downloaded_repo/patch/server.diff new file mode 100644 index 0000000..e7617e8 --- /dev/null +++ b/artifacts/downloaded_repo/patch/server.diff @@ -0,0 +1,22 @@ +--- a/server.js ++++ b/server.js +@@ -21,10 +21,17 @@ + + // Intialize Session + app.use(session({ +- secret: 'keyboard cat', ++ secret: process.env.SESSION_SECRET || 'default_secret', + resave: true, + saveUninitialized: true, +- cookie: { secure: false } ++ name: 'session_id', ++ cookie: { ++ secure: process.env.NODE_ENV === 'production', ++ httpOnly: true, ++ domain: 'example.com', ++ expires: new Date(Date.now() + 60 * 60 * 1000), // 1 hour ++ path: '/' ++ } + })) + + // Initialize Passport diff --git a/artifacts/downloaded_repo/repo b/artifacts/downloaded_repo/repo new file mode 160000 index 0000000..9ba473a --- /dev/null +++ b/artifacts/downloaded_repo/repo @@ -0,0 +1 @@ +Subproject commit 9ba473add536f66ac9007966acb2a775dd31277a diff --git a/artifacts/downloaded_repo/sast/before.json b/artifacts/downloaded_repo/sast/before.json new file mode 100644 index 0000000..cc0e134 --- /dev/null +++ b/artifacts/downloaded_repo/sast/before.json @@ -0,0 +1,620 @@ +{ + "version": "1.128.1", + "results": [ + { + "check_id": "javascript.sequelize.security.audit.sequelize-injection-express.express-sequelize-injection", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", + "start": { + "line": 11, + "col": 21, + "offset": 401 + }, + "end": { + "line": 11, + "col": 26, + "offset": 406 + }, + "extra": { + "message": "Detected a sequelize statement that is tainted by user-input. This could lead to SQL injection if the variable is user-controlled and is not properly sanitized. In order to prevent SQL injection, it is recommended to use parameterized queries or prepared statements.", + "metadata": { + "interfile": true, + "references": [ + "https://sequelize.org/docs/v6/core-concepts/raw-queries/#replacements" + ], + "category": "security", + "technology": [ + "express" + ], + "cwe": [ + "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')" + ], + "owasp": [ + "A01:2017 - Injection", + "A03:2021 - Injection" + ], + "cwe2022-top25": true, + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "HIGH", + "confidence": "HIGH", + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "SQL Injection" + ], + "source": "https://semgrep.dev/r/javascript.sequelize.security.audit.sequelize-injection-express.express-sequelize-injection", + "shortlink": "https://sg.run/gjoe" + }, + "severity": "ERROR", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-open-redirect.express-open-redirect", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", + "start": { + "line": 188, + "col": 16, + "offset": 4103 + }, + "end": { + "line": 188, + "col": 29, + "offset": 4116 + }, + "extra": { + "message": "The application redirects to a URL specified by user-supplied input `req` that is not validated. This could redirect users to malicious locations. Consider using an allow-list approach to validate URLs, or warn users they are being redirected to a third-party website.", + "metadata": { + "technology": [ + "express" + ], + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html" + ], + "cwe": [ + "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')" + ], + "category": "security", + "owasp": [ + "A01:2021 - Broken Access Control" + ], + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "MEDIUM", + "confidence": "HIGH", + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Open Redirect" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-open-redirect.express-open-redirect", + "shortlink": "https://sg.run/EpoP" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-third-party-object-deserialization.express-third-party-object-deserialization", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", + "start": { + "line": 218, + "col": 18, + "offset": 4721 + }, + "end": { + "line": 218, + "col": 81, + "offset": 4784 + }, + "extra": { + "message": "The following function call serialize.unserialize accepts user controlled data which can result in Remote Code Execution (RCE) through Object Deserialization. It is recommended to use secure data processing alternatives such as JSON.parse() and Buffer.from().", + "metadata": { + "interfile": true, + "technology": [ + "express" + ], + "category": "security", + "cwe": [ + "CWE-502: Deserialization of Untrusted Data" + ], + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html" + ], + "source_rule_url": [ + "https://github.com/ajinabraham/njsscan/blob/75bfbeb9c8d72999e4d527dfa2548f7f0f3cc48a/njsscan/rules/semantic_grep/eval/eval_deserialize.yaml" + ], + "owasp": [ + "A08:2017 - Insecure Deserialization", + "A08:2021 - Software and Data Integrity Failures" + ], + "cwe2022-top25": true, + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "HIGH", + "confidence": "HIGH", + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Insecure Deserialization " + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-third-party-object-deserialization.express-third-party-object-deserialization", + "shortlink": "https://sg.run/8W5j" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-libxml-noent.express-libxml-noent", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", + "start": { + "line": 235, + "col": 42, + "offset": 5344 + }, + "end": { + "line": 235, + "col": 82, + "offset": 5384 + }, + "extra": { + "message": "The libxml library processes user-input with the `noent` attribute is set to `true` which can lead to being vulnerable to XML External Entities (XXE) type attacks. It is recommended to set `noent` to `false` when using this feature to ensure you are protected.", + "metadata": { + "interfile": true, + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html" + ], + "technology": [ + "express" + ], + "category": "security", + "cwe": [ + "CWE-611: Improper Restriction of XML External Entity Reference" + ], + "owasp": [ + "A04:2017 - XML External Entities (XXE)", + "A05:2021 - Security Misconfiguration" + ], + "cwe2022-top25": true, + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "HIGH", + "confidence": "HIGH", + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "XML Injection" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-libxml-noent.express-libxml-noent", + "shortlink": "https://sg.run/Z75x" + }, + "severity": "ERROR", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-default-name", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", + "start": { + "line": 23, + "col": 9, + "offset": 655 + }, + "end": { + "line": 28, + "col": 3, + "offset": 769 + }, + "extra": { + "message": "Don’t use the default session cookie name Using the default session cookie name can open your app to attacks. The security issue posed is similar to X-Powered-By: a potential attacker can use it to fingerprint the server and target attacks accordingly.", + "metadata": { + "cwe": [ + "CWE-522: Insufficiently Protected Credentials" + ], + "owasp": [ + "A02:2017 - Broken Authentication", + "A04:2021 - Insecure Design" + ], + "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", + "category": "security", + "technology": [ + "express" + ], + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "LOW", + "confidence": "MEDIUM", + "references": [ + "https://owasp.org/Top10/A04_2021-Insecure_Design" + ], + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Cryptographic Issues" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-default-name", + "shortlink": "https://sg.run/1Z5x" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-domain", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", + "start": { + "line": 23, + "col": 9, + "offset": 655 + }, + "end": { + "line": 28, + "col": 3, + "offset": 769 + }, + "extra": { + "message": "Default session middleware settings: `domain` not set. It indicates the domain of the cookie; use it to compare against the domain of the server in which the URL is being requested. If they match, then check the path attribute next.", + "metadata": { + "cwe": [ + "CWE-522: Insufficiently Protected Credentials" + ], + "owasp": [ + "A02:2017 - Broken Authentication", + "A04:2021 - Insecure Design" + ], + "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", + "category": "security", + "technology": [ + "express" + ], + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "LOW", + "confidence": "MEDIUM", + "references": [ + "https://owasp.org/Top10/A04_2021-Insecure_Design" + ], + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Cryptographic Issues" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-domain", + "shortlink": "https://sg.run/rd41" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-expires", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", + "start": { + "line": 23, + "col": 9, + "offset": 655 + }, + "end": { + "line": 28, + "col": 3, + "offset": 769 + }, + "extra": { + "message": "Default session middleware settings: `expires` not set. Use it to set expiration date for persistent cookies.", + "metadata": { + "cwe": [ + "CWE-522: Insufficiently Protected Credentials" + ], + "owasp": [ + "A02:2017 - Broken Authentication", + "A04:2021 - Insecure Design" + ], + "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", + "category": "security", + "technology": [ + "express" + ], + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "LOW", + "confidence": "MEDIUM", + "references": [ + "https://owasp.org/Top10/A04_2021-Insecure_Design" + ], + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Cryptographic Issues" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-expires", + "shortlink": "https://sg.run/N4eG" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-httponly", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", + "start": { + "line": 23, + "col": 9, + "offset": 655 + }, + "end": { + "line": 28, + "col": 3, + "offset": 769 + }, + "extra": { + "message": "Default session middleware settings: `httpOnly` not set. It ensures the cookie is sent only over HTTP(S), not client JavaScript, helping to protect against cross-site scripting attacks.", + "metadata": { + "cwe": [ + "CWE-522: Insufficiently Protected Credentials" + ], + "owasp": [ + "A02:2017 - Broken Authentication", + "A04:2021 - Insecure Design" + ], + "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", + "category": "security", + "technology": [ + "express" + ], + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "LOW", + "confidence": "MEDIUM", + "references": [ + "https://owasp.org/Top10/A04_2021-Insecure_Design" + ], + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Cryptographic Issues" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-httponly", + "shortlink": "https://sg.run/ydBO" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-path", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", + "start": { + "line": 23, + "col": 9, + "offset": 655 + }, + "end": { + "line": 28, + "col": 3, + "offset": 769 + }, + "extra": { + "message": "Default session middleware settings: `path` not set. It indicates the path of the cookie; use it to compare against the request path. If this and domain match, then send the cookie in the request.", + "metadata": { + "cwe": [ + "CWE-522: Insufficiently Protected Credentials" + ], + "owasp": [ + "A02:2017 - Broken Authentication", + "A04:2021 - Insecure Design" + ], + "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", + "category": "security", + "technology": [ + "express" + ], + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "LOW", + "confidence": "MEDIUM", + "references": [ + "https://owasp.org/Top10/A04_2021-Insecure_Design" + ], + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Cryptographic Issues" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-path", + "shortlink": "https://sg.run/b7pd" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-secure", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", + "start": { + "line": 23, + "col": 9, + "offset": 655 + }, + "end": { + "line": 28, + "col": 3, + "offset": 769 + }, + "extra": { + "message": "Default session middleware settings: `secure` not set. It ensures the browser only sends the cookie over HTTPS.", + "metadata": { + "cwe": [ + "CWE-522: Insufficiently Protected Credentials" + ], + "owasp": [ + "A02:2017 - Broken Authentication", + "A04:2021 - Insecure Design" + ], + "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", + "category": "security", + "technology": [ + "express" + ], + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "LOW", + "confidence": "MEDIUM", + "references": [ + "https://owasp.org/Top10/A04_2021-Insecure_Design" + ], + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Cryptographic Issues" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-secure", + "shortlink": "https://sg.run/9oKz" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + }, + { + "check_id": "javascript.express.security.audit.express-session-hardcoded-secret.express-session-hardcoded-secret", + "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", + "start": { + "line": 24, + "col": 3, + "offset": 668 + }, + "end": { + "line": 24, + "col": 25, + "offset": 690 + }, + "extra": { + "message": "A hard-coded credential was detected. It is not recommended to store credentials in source-code, as this risks secrets being leaked and used by either an internal or external malicious adversary. It is recommended to use environment variables to securely provide credentials or retrieve credentials from a secure vault or HSM (Hardware Security Module).", + "metadata": { + "interfile": true, + "cwe": [ + "CWE-798: Use of Hard-coded Credentials" + ], + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" + ], + "owasp": [ + "A07:2021 - Identification and Authentication Failures" + ], + "category": "security", + "technology": [ + "express", + "secrets" + ], + "cwe2022-top25": true, + "cwe2021-top25": true, + "subcategory": [ + "vuln" + ], + "likelihood": "HIGH", + "impact": "HIGH", + "confidence": "HIGH", + "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", + "vulnerability_class": [ + "Hard-coded Secrets" + ], + "source": "https://semgrep.dev/r/javascript.express.security.audit.express-session-hardcoded-secret.express-session-hardcoded-secret", + "shortlink": "https://sg.run/LYvG" + }, + "severity": "WARNING", + "fingerprint": "requires login", + "lines": "requires login", + "validation_state": "NO_VALIDATOR", + "engine_kind": "OSS" + } + } + ], + "errors": [], + "paths": { + "scanned": [ + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\config\\db.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\config\\server.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\config\\vulns.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\authHandler.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\passport.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\models\\index.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\models\\product.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\models\\user.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\routes\\app.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\routes\\main.js", + "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js" + ] + }, + "time": { + "rules": [], + "rules_parse_time": 0.4553208351135254, + "profiling_times": { + "config_time": 1.6937980651855469, + "core_time": 1.868072271347046, + "ignores_time": 0.0, + "total_time": 3.5632758140563965 + }, + "parsing_time": { + "total_time": 0.07409214973449707, + "per_file_time": { + "mean": 0.007409214973449707, + "std_dev": 8.423851878944789e-05 + }, + "very_slow_files": [] + }, + "targets": [], + "total_bytes": 0, + "max_memory_bytes": 188583296 + }, + "skipped_rules": [] +} \ No newline at end of file diff --git a/artifacts/downloaded_repo/sast/merged_snippets.json b/artifacts/downloaded_repo/sast/merged_snippets.json new file mode 100644 index 0000000..a1126f0 --- /dev/null +++ b/artifacts/downloaded_repo/sast/merged_snippets.json @@ -0,0 +1,52 @@ +[ + { + "input": "var db = require('../models')\nvar bCrypt = require('bcrypt')\nconst exec = require('child_process').exec;\nvar mathjs = require('mathjs')\nvar libxmljs = require(\"libxmljs\");\nvar serialize = require(\"node-serialize\")\nconst Op = db.Sequelize.Op\n\nmodule.exports.userSearch = function (req, res) {\n\tvar query = \"SELECT name,id FROM Users WHERE login='\" + req.body.login + \"'\";\n\tdb.sequelize.query(query, {\n\t\tmodel: db.User\n\t}).then(user => {\n\t\tif (user.length) {\n\t\t\tvar output = {\n\t\t\t\tuser: {\n\t\t\t\t\tname: user[0].name,\n\t\t\t\t\tid: user[0].id\n\t\t\t\t}\n\t\t\t}\n\t\t\tres.render('app/usersearch', {\n\t\t\t\toutput: output\n\t\t\t})\n\t\t} else {\n\t\t\treq.flash('warning', 'User not found')\n\t\t\tres.render('app/usersearch', {\n\t\t\t\toutput: null\n\t\t\t})\n\t\t}\n\t}).catch(err => {\n\t\treq.flash('danger', 'Internal Error')\n\t\tres.render('app/usersearch', {\n\t\t\toutput: null\n\t\t})\n\t})\n}\n\nmodule.exports.ping = function (req, res) {\n\texec('ping -c 2 ' + req.body.address, function (err, stdout, stderr) {\n\t\toutput = stdout + stderr\n\t\tres.render('app/ping', {\n\t\t\toutput: output\n\t\t})\n\t})\n}\n\nmodule.exports.listProducts = function (req, res) {\n\tdb.Product.findAll().then(products => {\n\t\toutput = {\n\t\t\tproducts: products\n\t\t}\n\t\tres.render('app/products', {\n\t\t\toutput: output\n\t\t})\n\t})\n}\n\nmodule.exports.productSearch = function (req, res) {\n\tdb.Product.findAll({\n\t\twhere: {\n\t\t\tname: {\n\t\t\t\t[Op.like]: '%' + req.body.name + '%'\n\t\t\t}\n\t\t}\n\t}).then(products => {\n\t\toutput = {\n\t\t\tproducts: products,\n\t\t\tsearchTerm: req.body.name\n\t\t}\n\t\tres.render('app/products', {\n\t\t\toutput: output\n\t\t})\n\t})\n}\n\nmodule.exports.modifyProduct = function (req, res) {\n\tif (!req.query.id || req.query.id == '') {\n\t\toutput = {\n\t\t\tproduct: {}\n\t\t}\n\t\tres.render('app/modifyproduct', {\n\t\t\toutput: output\n\t\t})\n\t} else {\n\t\tdb.Product.find({\n\t\t\twhere: {\n\t\t\t\t'id': req.query.id\n\t\t\t}\n\t\t}).then(product => {\n\t\t\tif (!product) {\n\t\t\t\tproduct = {}\n\t\t\t}\n\t\t\toutput = {\n\t\t\t\tproduct: product\n\t\t\t}\n\t\t\tres.render('app/modifyproduct', {\n\t\t\t\toutput: output\n\t\t\t})\n\t\t})\n\t}\n}\n\nmodule.exports.modifyProductSubmit = function (req, res) {\n\tif (!req.body.id || req.body.id == '') {\n\t\treq.body.id = 0\n\t}\n\tdb.Product.find({\n\t\twhere: {\n\t\t\t'id': req.body.id\n\t\t}\n\t}).then(product => {\n\t\tif (!product) {\n\t\t\tproduct = new db.Product()\n\t\t}\n\t\tproduct.code = req.body.code\n\t\tproduct.name = req.body.name\n\t\tproduct.description = req.body.description\n\t\tproduct.tags = req.body.tags\n\t\tproduct.save().then(p => {\n\t\t\tif (p) {\n\t\t\t\treq.flash('success', 'Product added/modified!')\n\t\t\t\tres.redirect('/app/products')\n\t\t\t}\n\t\t}).catch(err => {\n\t\t\toutput = {\n\t\t\t\tproduct: product\n\t\t\t}\n\t\t\treq.flash('danger',err)\n\t\t\tres.render('app/modifyproduct', {\n\t\t\t\toutput: output\n\t\t\t})\n\t\t})\n\t})\n}\n\nmodule.exports.userEdit = function (req, res) {\n\tres.render('app/useredit', {\n\t\tuserId: req.user.id,\n\t\tuserEmail: req.user.email,\n\t\tuserName: req.user.name\n\t})\n}\n\nmodule.exports.userEditSubmit = function (req, res) {\n\tdb.User.find({\n\t\twhere: {\n\t\t\t'id': req.body.id\n\t\t}\t\t\n\t}).then(user =>{\n\t\tif(req.body.password.length>0){\n\t\t\tif(req.body.password.length>0){\n\t\t\t\tif (req.body.password == req.body.cpassword) {\n\t\t\t\t\tuser.password = bCrypt.hashSync(req.body.password, bCrypt.genSaltSync(10), null)\n\t\t\t\t}else{\n\t\t\t\t\treq.flash('warning', 'Passwords dont match')\n\t\t\t\t\tres.render('app/useredit', {\n\t\t\t\t\t\tuserId: req.user.id,\n\t\t\t\t\t\tuserEmail: req.user.email,\n\t\t\t\t\t\tuserName: req.user.name,\n\t\t\t\t\t})\n\t\t\t\t\treturn\t\t\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\treq.flash('warning', 'Invalid Password')\n\t\t\t\tres.render('app/useredit', {\n\t\t\t\t\tuserId: req.user.id,\n\t\t\t\t\tuserEmail: req.user.email,\n\t\t\t\t\tuserName: req.user.name,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tuser.email = req.body.email\n\t\tuser.name = req.body.name\n\t\tuser.save().then(function () {\n\t\t\treq.flash('success',\"Updated successfully\")\n\t\t\tres.render('app/useredit', {\n\t\t\t\tuserId: req.body.id,\n\t\t\t\tuserEmail: req.body.email,\n\t\t\t\tuserName: req.body.name,\n\t\t\t})\n\t\t})\n\t})\n}\n\nmodule.exports.redirect = function (req, res) {\n\tif (req.query.url) {\n\t\tres.redirect(req.query.url)\n\t} else {\n\t\tres.send('invalid redirect url')\n\t}\n}\n\nmodule.exports.calc = function (req, res) {\n\tif (req.body.eqn) {\n\t\tres.render('app/calc', {\n\t\t\toutput: mathjs.eval(req.body.eqn)\n\t\t})\n\t} else {\n\t\tres.render('app/calc', {\n\t\t\toutput: 'Enter a valid math string like (3+3)*2'\n\t\t})\n\t}\n}\n\nmodule.exports.listUsersAPI = function (req, res) {\n\tdb.User.findAll({}).then(users => {\n\t\tres.status(200).json({\n\t\t\tsuccess: true,\n\t\t\tusers: users\n\t\t})\n\t})\n}\n\nmodule.exports.bulkProductsLegacy = function (req,res){\n\t// TODO: Deprecate this soon\n\tif(req.files.products){\n\t\tvar products = serialize.unserialize(req.files.products.data.toString('utf8'))\n\t\tproducts.forEach( function (product) {\n\t\t\tvar newProduct = new db.Product()\n\t\t\tnewProduct.name = product.name\n\t\t\tnewProduct.code = product.code\n\t\t\tnewProduct.tags = product.tags\n\t\t\tnewProduct.description = product.description\n\t\t\tnewProduct.save()\n\t\t})\n\t\tres.redirect('/app/products')\n\t}else{\n\t\tres.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true})\n\t}\n}\n\nmodule.exports.bulkProducts = function(req, res) {\n\tif (req.files.products && req.files.products.mimetype=='text/xml'){\n\t\tvar products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true})\n\t\tproducts.root().childNodes().forEach( product => {\n\t\t\tvar newProduct = new db.Product()\n\t\t\tnewProduct.name = product.childNodes()[0].text()\n\t\t\tnewProduct.code = product.childNodes()[1].text()\n\t\t\tnewProduct.tags = product.childNodes()[2].text()\n\t\t\tnewProduct.description = product.childNodes()[3].text()\n\t\t\tnewProduct.save()\n\t\t})\n\t\tres.redirect('/app/products')\n\t}else{\n\t\tres.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:false})\n\t}\n}\n", + "idx": null, + "start_line": 11, + "end_line": 235, + "snippet": "\t\tres.redirect(req.query.url)\n\t\tvar products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true})\n\t\tvar products = serialize.unserialize(req.files.products.data.toString('utf8'))\n\tdb.sequelize.query(query, {", + "message": "Detected a sequelize statement that is tainted by user-input. This could lead to SQL injection if the variable is user-controlled and is not properly sanitized. In order to prevent SQL injection, it is recommended to use parameterized queries or prepared statements. | The application redirects to a URL specified by user-supplied input `req` that is not validated. This could redirect users to malicious locations. Consider using an allow-list approach to validate URLs, or warn users they are being redirected to a third-party website. | The following function call serialize.unserialize accepts user controlled data which can result in Remote Code Execution (RCE) through Object Deserialization. It is recommended to use secure data processing alternatives such as JSON.parse() and Buffer.from(). | The libxml library processes user-input with the `noent` attribute is set to `true` which can lead to being vulnerable to XML External Entities (XXE) type attacks. It is recommended to set `noent` to `false` when using this feature to ensure you are protected.", + "vulnerability_class": [ + "Insecure Deserialization ", + "Open Redirect", + "SQL Injection", + "XML Injection" + ], + "cwe": [ + "CWE-502: Deserialization of Untrusted Data", + "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')", + "CWE-611: Improper Restriction of XML External Entity Reference", + "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')" + ], + "severity": "ERROR", + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html", + "https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html", + "https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html", + "https://sequelize.org/docs/v6/core-concepts/raw-queries/#replacements" + ], + "path": "core/appHandler.js" + }, + { + "input": "var express = require('express')\nvar bodyParser = require('body-parser')\nvar passport = require('passport')\nvar session = require('express-session')\nvar ejs = require('ejs')\nvar morgan = require('morgan')\nconst fileUpload = require('express-fileupload');\nvar config = require('./config/server')\n\n//Initialize Express\nvar app = express()\nrequire('./core/passport')(passport)\napp.use(express.static('public'))\napp.set('view engine','ejs')\napp.use(morgan('tiny'))\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(fileUpload());\n\n// Enable for Reverse proxy support\n// app.set('trust proxy', 1) \n\n// Intialize Session\napp.use(session({\n secret: 'keyboard cat',\n resave: true,\n saveUninitialized: true,\n cookie: { secure: false }\n}))\n\n// Initialize Passport\napp.use(passport.initialize())\napp.use(passport.session())\n\n// Initialize express-flash\napp.use(require('express-flash')());\n\n// Routing\napp.use('/app',require('./routes/app')())\napp.use('/',require('./routes/main')(passport))\n\n// Start Server\napp.listen(config.port, config.listen)", + "idx": null, + "start_line": 23, + "end_line": 28, + "snippet": " cookie: { secure: false }\n resave: true,\n saveUninitialized: true,\n secret: 'keyboard cat',\napp.use(session({\n}))", + "message": "A hard-coded credential was detected. It is not recommended to store credentials in source-code, as this risks secrets being leaked and used by either an internal or external malicious adversary. It is recommended to use environment variables to securely provide credentials or retrieve credentials from a secure vault or HSM (Hardware Security Module). | Default session middleware settings: `domain` not set. It indicates the domain of the cookie; use it to compare against the domain of the server in which the URL is being requested. If they match, then check the path attribute next. | Default session middleware settings: `expires` not set. Use it to set expiration date for persistent cookies. | Default session middleware settings: `httpOnly` not set. It ensures the cookie is sent only over HTTP(S), not client JavaScript, helping to protect against cross-site scripting attacks. | Default session middleware settings: `path` not set. It indicates the path of the cookie; use it to compare against the request path. If this and domain match, then send the cookie in the request. | Default session middleware settings: `secure` not set. It ensures the browser only sends the cookie over HTTPS. | Don’t use the default session cookie name Using the default session cookie name can open your app to attacks. The security issue posed is similar to X-Powered-By: a potential attacker can use it to fingerprint the server and target attacks accordingly.", + "vulnerability_class": [ + "Cryptographic Issues", + "Hard-coded Secrets" + ], + "cwe": [ + "CWE-522: Insufficiently Protected Credentials", + "CWE-798: Use of Hard-coded Credentials" + ], + "severity": "WARNING", + "references": [ + "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", + "https://owasp.org/Top10/A04_2021-Insecure_Design" + ], + "path": "server.js" + } +] \ No newline at end of file diff --git a/artifacts/downloaded_repo/snippets/snippet_core_appHandler.js.json b/artifacts/downloaded_repo/snippets/snippet_core_appHandler.js.json new file mode 100644 index 0000000..1451021 --- /dev/null +++ b/artifacts/downloaded_repo/snippets/snippet_core_appHandler.js.json @@ -0,0 +1 @@ +"\t\tres.redirect(req.query.url)\n\t\tvar products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true})\n\t\tvar products = serialize.unserialize(req.files.products.data.toString('utf8'))\n\tdb.sequelize.query(query, {" \ No newline at end of file diff --git a/artifacts/downloaded_repo/snippets/snippet_server.js.json b/artifacts/downloaded_repo/snippets/snippet_server.js.json new file mode 100644 index 0000000..8a0d1c0 --- /dev/null +++ b/artifacts/downloaded_repo/snippets/snippet_server.js.json @@ -0,0 +1 @@ +" cookie: { secure: false }\n resave: true,\n saveUninitialized: true,\n secret: 'keyboard cat',\napp.use(session({\n}))" \ No newline at end of file diff --git a/sast/before.json b/sast/before.json new file mode 100644 index 0000000..c79d8e2 --- /dev/null +++ b/sast/before.json @@ -0,0 +1 @@ +{"version":"1.128.1","results":[],"errors":[{"code":2,"level":"error","type":"SemgrepError","message":"Invalid scanning root: repo"}],"paths":{"scanned":[]},"skipped_rules":[]} \ No newline at end of file diff --git a/src/autofic_core/app.py b/src/autofic_core/app.py index 4aa8064..9ded461 100644 --- a/src/autofic_core/app.py +++ b/src/autofic_core/app.py @@ -1,12 +1,13 @@ import os import sys -from pathlib import Path +import time import traceback - +from pathlib import Path from rich.console import Console + from autofic_core.errors import * -from autofic_core.utils.ui_utils import print_help_message -from autofic_core.pipeline import AutoFiCPipeline +from autofic_core.utils.ui_utils import print_help_message, print_divider +from autofic_core.pipeline import AutoFiCPipeline from autofic_core.log.log_writer import LogManager from autofic_core.log.log_generator import LogGenerator @@ -31,7 +32,7 @@ def __init__(self, explain, repo, save_dir, sast, llm, llm_retry, patch, pr): def run(self): try: - self._validate_options() + self.validate_options() if self.explain: print_help_message() return @@ -50,7 +51,7 @@ def run(self): pipeline.run() if self.pr: - self._run_pr(pipeline) + self.run_pr() except AutoficError as e: console.print(str(e), style="red") @@ -61,7 +62,7 @@ def run(self): console.print(traceback.format_exc(), style="red") sys.exit(1) - def _validate_options(self): + def validate_options(self): if not self.repo: raise NoRepositoryError() if not self.save_dir: @@ -75,55 +76,109 @@ def _validate_options(self): if not self.patch and self.pr: raise PRWithoutPatchError() - def _run_pr(self, pipeline): - # PR automation - branch_num = 1 + def run_pr(self): + try: + print_divider("PR Automation Stage") + + pr_procedure = self.initialize_pr_procedure() + + console.print("[1] Initializing PR process & checking branches...\n", style="bold cyan") + time.sleep(0.5) + pr_procedure.post_init() + pr_procedure.mv_workdir() + pr_procedure.check_branch_exists() + + console.print("\n[2] Notifying webhooks...\n", style="bold cyan") + time.sleep(0.5) + self.notify_webhooks(pr_procedure) + + console.print("\n[3] Creating and pushing PR workflow YAML...\n", style="bold cyan") + time.sleep(0.5) + self.handle_pr_yml(pr_procedure) + + console.print("\n[4] Changing files for the pull request...\n", style="bold cyan") + time.sleep(0.5) + pr_procedure.change_files() + + console.print("\n[5] Updating branch and creating Pull Request...\n", style="bold cyan") + time.sleep(0.5) + pr_procedure.current_main_branch() + pr_procedure.generate_pr() + pr_number = pr_procedure.create_pr() + + console.print(f"\n[ SUCCESS ] Pull Request created successfully!\n", style="bold green") + time.sleep(0.5) + + self.finalize_logging(pr_procedure, pr_number) + + except Exception as e: + console.print(f"[ PR ERROR ] {e}", style="bold red") + console.print(traceback.format_exc(), style="red") + raise + + def initialize_pr_procedure(self): base_branch = 'main' - branch_name = "UNKNOWN" - repo_name = "UNKOWN" - upstream_owner = "UNKOWN" save_dir = Path(self.save_dir).joinpath('repo') repo_url = self.repo.rstrip('/').replace('.git', '') - secret_discord = os.getenv('DISCORD_WEBHOOK_URL') - secret_slack = os.getenv('SLACK_WEBHOOK_URL') + json_path = str(Path(self.save_dir).joinpath("sast") / "before.json") token = os.getenv('GITHUB_TOKEN') user_name = os.getenv('USER_NAME') - - # Define PRProcedure class - json_path = str(Path(self.save_dir).joinpath("sast") / "before.json") tool = self.sast.lower() if self.sast else None - pr_procedure = PRProcedure( - base_branch, repo_name, upstream_owner, - save_dir, repo_url, token, user_name, json_path, tool + + return PRProcedure( + base_branch=base_branch, + repo_name="UNKNOWN", + upstream_owner="UNKNOWN", + save_dir=save_dir, + repo_url=repo_url, + token=token, + user_name=user_name, + json_path=json_path, + tool=tool ) - # Chapter 1 - pr_procedure.post_init() + + def notify_webhooks(self, pr_procedure): + secret_discord = os.getenv('DISCORD_WEBHOOK_URL') + secret_slack = os.getenv('SLACK_WEBHOOK_URL') + + user_name = pr_procedure.user_name repo_name = pr_procedure.repo_name - upstream_owner = pr_procedure.upstream_owner - # Chaper 2 - pr_procedure.mv_workdir() - # Chapter 3 - pr_procedure.check_branch_exists() - branch_name = pr_procedure.branch_name - # Chapter 4 + token = pr_procedure.token + EnvEncrypy(user_name, repo_name, token).webhook_secret_notifier('DISCORD_WEBHOOK_URL', secret_discord) EnvEncrypy(user_name, repo_name, token).webhook_secret_notifier('SLACK_WEBHOOK_URL', secret_slack) - # Chapter 5 - AboutYml().create_pr_yml() - AboutYml().push_pr_yml(user_name, repo_name, token, branch_name) - # Chapter 6 - pr_procedure.change_files() - # Chapter 7 - pr_procedure.current_main_branch() - # Chapter 8,9 - pr_procedure.generate_pr() - pr_number = pr_procedure.create_pr() - - # for log - repo_data = self.log_gen.generate_repo_log(save_dir=Path(self.save_dir), name=repo_name, owner=upstream_owner, - repo_url=repo_url, sastTool=tool, rerun=self.llm_retry) - pr_log_data = self.log_gen.generate_pr_log(owner=upstream_owner, repo=repo_name, user_name=user_name, - repo_url=repo_url, repo_hash=repo_data["repo_hash"], - pr_number=pr_number) + + def handle_pr_yml(self, pr_procedure): + user_name = pr_procedure.user_name + repo_name = pr_procedure.repo_name + token = pr_procedure.token + branch_name = pr_procedure.branch_name + + yml_handler = AboutYml() + yml_handler.create_pr_yml() + yml_handler.push_pr_yml(user_name, repo_name, token, branch_name) + + def finalize_logging(self, pr_procedure, pr_number): + tool = self.sast.lower() if self.sast else None + repo_url = self.repo.rstrip('/').replace('.git', '') + + repo_data = self.log_gen.generate_repo_log( + save_dir=Path(self.save_dir), + name=pr_procedure.repo_name, + owner=pr_procedure.upstream_owner, + repo_url=repo_url, + sastTool=tool, + rerun=self.llm_retry + ) + + pr_log_data = self.log_gen.generate_pr_log( + owner=pr_procedure.upstream_owner, + repo=pr_procedure.repo_name, + user_name=pr_procedure.user_name, + repo_url=repo_url, + repo_hash=repo_data["repo_hash"], + pr_number=pr_number + ) + self.log_manager.add_pr_log(pr_log_data) self.log_manager.add_repo_status(repo_data) \ No newline at end of file diff --git a/src/autofic_core/patch/apply_patch.py b/src/autofic_core/patch/apply_patch.py index dfec9f3..b03c9d2 100644 --- a/src/autofic_core/patch/apply_patch.py +++ b/src/autofic_core/patch/apply_patch.py @@ -50,7 +50,7 @@ def apply_all(self) -> bool: failed_patches.append(patch_file) if failed_patches: - self.console.print(f"\n[cyan][ INFO ] {len(failed_patches)} patches failed → trying overwrite from parsed (see logs)[/cyan]\n") + self.console.print(f"[cyan][ INFO ] {len(failed_patches)} patches failed → trying overwrite from parsed (see logs)[/cyan]\n") for patch_file in failed_patches: self.overwrite_with_parsed(patch_file) @@ -66,7 +66,7 @@ def apply_single(self, patch_file: Path) -> bool: ) if result.returncode == 0: - self.console.print(f"[white][✓] Patch applied: {patch_file.name}[/white]") + self.console.print(f"[white][✓] Patch applied: {patch_file.name}[/white]\n") return True else: self.console.print(PatchFailMessages.PATCH_FAILED.format(patch_file.name), style="yellow") @@ -161,7 +161,7 @@ def overwrite_with_parsed(self, patch_file: Path) -> bool: try: shutil.copyfile(matched_file, repo_file) - self.console.print(f"[white][✓] Overwrote repo file: {repo_file}[/white]") + self.console.print(f"[white][✓] Overwrote repo file: {repo_file}[/white]\n") return True except Exception as e: self.console.print(PatchErrorMessages.OVERWRITE_FAILED.format(e), style="red") diff --git a/src/autofic_core/pipeline.py b/src/autofic_core/pipeline.py index e5528fb..62a88a5 100644 --- a/src/autofic_core/pipeline.py +++ b/src/autofic_core/pipeline.py @@ -52,14 +52,14 @@ def clone(self): try: if self.handler.needs_fork: - console.print("\nAttempting to fork the repository...\n", style="cyan") + console.print("Attempting to fork the repository...\n", style="cyan") self.handler.fork() time.sleep(1) - console.print("\n[ SUCCESS ] Fork completed\n", style="green") + console.print("[ SUCCESS ] Fork completed\n", style="green") self.clone_path = Path( self.handler.clone_repo(save_dir=str(self.save_dir), use_forked=self.handler.needs_fork)) - console.print(f"\n[ SUCCESS ] Repository cloned successfully: {self.clone_path}\n", style="green") + console.print(f"[ SUCCESS ] Repository cloned successfully: {self.clone_path}", style="green") except ForkFailedError as e: sys.exit(1) @@ -77,8 +77,10 @@ def __init__(self, repo_path: Path, save_dir: Path): self.save_dir = save_dir def run(self): + description = "Running Semgrep...".ljust(28) with create_progress() as progress: - task = progress.add_task("[cyan]Running Semgrep...", total=100) + task = progress.add_task(description, total=100) + start = time.time() runner = SemgrepRunner(repo_path=str(self.repo_path), rule="p/javascript") result = runner.run_semgrep() @@ -123,8 +125,10 @@ def __init__(self, repo_path: Path, save_dir: Path): self.save_dir = save_dir def run(self): + description = "Running CodeQL...".ljust(28) with create_progress() as progress: - task = progress.add_task("[cyan]Running CodeQL...", total=100) + task = progress.add_task(description, total=100) + start = time.time() runner = CodeQLRunner(repo_path=str(self.repo_path)) result_path = runner.run_codeql() @@ -166,10 +170,12 @@ class SnykCodeHandler: def __init__(self, repo_path: Path, save_dir: Path): self.repo_path = repo_path self.save_dir = save_dir - + def run(self): + description = "Running SnykCode...".ljust(28) with create_progress() as progress: - task = progress.add_task("[cyan]Running SnykCode...", total=100) + task = progress.add_task(description, total=100) + start = time.time() runner = SnykCodeRunner(repo_path=str(self.repo_path)) result = runner.run_snykcode() @@ -267,7 +273,6 @@ def __init__(self, sast_result_path: Path, repo_path: Path, save_dir: Path, tool self.patch_dir = save_dir / "patch" def run(self): - console.print() print_divider("LLM Response Generation Stage") prompt_generator = PromptGenerator() @@ -284,10 +289,10 @@ def run(self): llm = LLMRunner() self.llm_output_dir.mkdir(parents=True, exist_ok=True) - - console.print("Starting GPT response generation\n") + + description = "Generating LLM responses... \n".ljust(28) with create_progress() as progress: - task = progress.add_task("[magenta]Generating LLM responses...", total=len(prompts)) + task = progress.add_task(description, total=len(prompts)) for p in prompts: response = llm.run(p.prompt) @@ -298,7 +303,7 @@ def run(self): time.sleep(0.01) progress.update(task, completed=100) - console.print(f"\n[ SUCCESS ] LLM responses saved → {self.llm_output_dir}\n", style="green") + console.print(f"[ SUCCESS ] LLM responses saved → {self.llm_output_dir}", style="green") return prompts, file_snippets def retry(self): @@ -370,7 +375,7 @@ def run(self): success = patch_applier.apply_all() if success: - console.print(f"\n[ SUCCESS ] All patches successfully applied\n", style="green") + console.print(f"[ SUCCESS ] All patches successfully applied", style="green") else: console.print(f"\n[ WARN ] Some patches failed to apply → {self.repo_dir}\n", style="yellow") diff --git a/src/autofic_core/pr_auto/create_yml.py b/src/autofic_core/pr_auto/create_yml.py index d2b595c..57e49c8 100644 --- a/src/autofic_core/pr_auto/create_yml.py +++ b/src/autofic_core/pr_auto/create_yml.py @@ -18,7 +18,9 @@ """ import os import subprocess -import click +from rich.console import Console + +console = Console() # Handles creation and git operations for GitHub Actions workflow YAML files class AboutYml: @@ -82,7 +84,7 @@ def push_pr_yml(self, user_name, repo_name, token, branch_name): """ repo_url = f'https://x-access-token:{token}@github.com/{user_name}/{repo_name}.git' subprocess.run(['git', 'remote', 'set-url', 'origin', repo_url], check=True) - click.secho("[ INFO ] Pushing the generated .github/workflows/pr_notify.yml.", fg="yellow") + console.print("[ INFO ] Created GitHub Actions workflow file: pr_notify.yml\n", style="white") subprocess.run(['git', 'add', '.github/workflows/pr_notify.yml'], check=True) - subprocess.run(['git', 'commit', '-m', "[Autofic] Create package.json and CI workflow"], check=True) - subprocess.run(['git', 'push', 'origin', branch_name], check=True) + subprocess.run(['git', 'commit', '-m', "[ AutoFiC ] Create package.json and CI workflow"], check=True) + subprocess.run(['git', 'push', 'origin', branch_name], check=True) \ No newline at end of file diff --git a/src/autofic_core/pr_auto/env_encrypt.py b/src/autofic_core/pr_auto/env_encrypt.py index a2c1573..7a74bee 100644 --- a/src/autofic_core/pr_auto/env_encrypt.py +++ b/src/autofic_core/pr_auto/env_encrypt.py @@ -14,69 +14,41 @@ # limitations under the License. # ============================================================================= -"""Contains their functional aliases. -""" - import base64 import requests from nacl import public, encoding +from rich.console import Console + +console = Console() class EnvEncrypy: - """ - Utility class for encrypting and registering GitHub Actions secrets (e.g., webhooks) - using the repository's public key. - """ def __init__(self, user_name, repo_name, token): - """ - Initialize with GitHub repository and user credentials. - - :param user_name: GitHub username (owner) - :param repo_name: GitHub repository name - :param token: GitHub personal access token - """ self.user_name = user_name self.repo_name = repo_name self.token = token def webhook_secret_notifier(self, secret_name: str, webhook_url: str): - """ - Registers a webhook URL as a secret in the target GitHub repository. - This fetches the repo's public key, encrypts the webhook URL, - and stores it as a new Actions secret. - - :param secret_name: The name of the secret to be created/updated - :param webhook_url: The actual webhook URL to store (as secret) - """ url = f'https://api.github.com/repos/{self.user_name}/{self.repo_name}/actions/secrets/public-key' headers = {'Authorization': f'token {self.token}'} resp = requests.get(url, headers=headers) pubkey_info = resp.json() - # Prevent KeyError (validates key info exists) if 'key_id' not in pubkey_info or 'key' not in pubkey_info: - print(f"[ERROR] Invalid public key info: {pubkey_info}") + console.print(f"[ ERROR ] Invalid public key info: {pubkey_info}", style="red") return key_id = pubkey_info['key_id'] encrypted_value = self.encrypt(pubkey_info['key'], webhook_url) - # Register the secret in the repository url2 = f'https://api.github.com/repos/{self.user_name}/{self.repo_name}/actions/secrets/{secret_name}' payload = { "encrypted_value": encrypted_value, "key_id": key_id } resp2 = requests.put(url2, headers={**headers, 'Content-Type': 'application/json'}, json=payload) - print(f"Secret registered: {secret_name}, {resp2.status_code}, {resp2.text}") + console.print(f"[ INFO ] Secret registered: {secret_name}, {resp2.status_code}, {resp2.text}", style="white") def encrypt(self, public_key: str, secret_value: str) -> str: - """ - Encrypts a secret value using the repository's Base64-encoded public key. - - :param public_key: Repository's public key (Base64-encoded) - :param secret_value: Secret value (plain text) to encrypt - :return: Encrypted secret value (Base64-encoded string) - """ public_key = public.PublicKey(public_key, encoding.Base64Encoder()) sealed_box = public.SealedBox(public_key) encrypted = sealed_box.encrypt(secret_value.encode("utf-8")) diff --git a/src/autofic_core/pr_auto/pr_procedure.py b/src/autofic_core/pr_auto/pr_procedure.py index 6610595..034a52b 100644 --- a/src/autofic_core/pr_auto/pr_procedure.py +++ b/src/autofic_core/pr_auto/pr_procedure.py @@ -25,12 +25,16 @@ import subprocess from pathlib import Path from typing import List +from rich.console import Console from collections import defaultdict + from autofic_core.sast.snippet import BaseSnippet from autofic_core.sast.semgrep.preprocessor import SemgrepPreprocessor from autofic_core.sast.codeql.preprocessor import CodeQLPreprocessor from autofic_core.sast.snykcode.preprocessor import SnykCodePreprocessor +console = Console() + class PRProcedure: """ Handles all modules required for the pull request workflow. @@ -129,7 +133,7 @@ def change_files(self): if os.path.exists(path): subprocess.run(['git', 'reset', '-q', path], check=False) - commit_message = f"[Autofic] {self.vulnerabilities} malicious code detected!!" + commit_message = f"[ AutoFiC ] {self.vulnerabilities} malicious code detected!!" subprocess.run(['git', 'commit', '-m', commit_message], check=True) try: @@ -158,7 +162,7 @@ def generate_pr(self) -> str: Uses vulnerability scan results (by semgrep) to generate a detailed PR body. If llm_generator implemented, then pr_body will add llm_result. """ - print(f"[INFO] Creating PR on {self.user_name}/{self.repo_name}. base branch: {self.base_branch}") + console.print(f"[ INFO ] Creating PR on {self.user_name}/{self.repo_name}. Base branch: {self.base_branch}\n", style="white") pr_url = f"https://api.github.com/repos/{self.user_name}/{self.repo_name}/pulls" if self.tool == "semgrep": snippets = SemgrepPreprocessor.preprocess(self.json_path) @@ -170,7 +174,7 @@ def generate_pr(self) -> str: raise ValueError(f"Unknown tool: {self.tool}") pr_body = self.generate_markdown(snippets) data_post = { - "title": f"[Autofic] Security Patch {datetime.datetime.now().strftime('%Y-%m-%d')}", + "title": f"[ AutoFiC ] Security Patch {datetime.datetime.now().strftime('%Y-%m-%d')}", "head": f"{self.user_name}:{self.branch_name}", "base": self.base_branch, "body": pr_body @@ -254,7 +258,7 @@ def create_pr(self): snippets = SnykCodePreprocessor.preprocess(self.json_path) pr_body = self.generate_markdown(snippets) data_post = { - "title": f"[Autofic] Security Patch {datetime.datetime.now().strftime('%Y-%m-%d')}", + "title": f"[ AutoFiC ] Security Patch {datetime.datetime.now().strftime('%Y-%m-%d')}", "head": f"{self.user_name}:{self.pr_branch}", "base": self.base_branch, "body": pr_body @@ -329,7 +333,7 @@ def generate_markdown_from_llm(llm_path: str) -> str: md = [ "## 🔧 About This Pull Request", - "This patch was automatically created by **[AutoFiC](https://autofic.github.io)**,\nan open-source framework that combines **static analysis tools** with **AI-driven remediation**.", + "This patch was automatically created by **[ AutoFiC ](https://autofic.github.io)**,\nan open-source framework that combines **static analysis tools** with **AI-driven remediation**.", "\nUsing **Semgrep**, **CodeQL**, and **Snyk Code**, AutoFiC detected potential **security flaws** and applied **verified fixes**.", "Each patch includes **contextual explanations** powered by a **large language model** to support **review and decision-making**.", "", diff --git a/src/autofic_core/utils/progress_utils.py b/src/autofic_core/utils/progress_utils.py index 1c6c75f..0797644 100644 --- a/src/autofic_core/utils/progress_utils.py +++ b/src/autofic_core/utils/progress_utils.py @@ -1,10 +1,16 @@ from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn +from rich.style import Style def create_progress(): return Progress( - SpinnerColumn(), - TextColumn("[bold blue]{task.description}"), - BarColumn(bar_width=None, style="green", complete_style="green"), - TextColumn("[progress.percentage]{task.percentage:>3.0f}%"), + SpinnerColumn(style="cyan"), + TextColumn("{task.description}", style=Style(color="cyan", bold=True), justify="left"), + BarColumn( + bar_width=55, + style=Style(color="blue"), + complete_style=Style(color="bright_blue"), + finished_style=Style(color="bright_blue", bold=True), + ), + TextColumn("{task.percentage:>3.0f}%", style=Style(color="blue", bold=True)), transient=False ) \ No newline at end of file diff --git a/src/autofic_core/utils/ui_utils.py b/src/autofic_core/utils/ui_utils.py index 992bfb0..4ee444c 100644 --- a/src/autofic_core/utils/ui_utils.py +++ b/src/autofic_core/utils/ui_utils.py @@ -5,9 +5,17 @@ console = Console() +def print_divider(title: str): + diamond = "◆" + stage = f"[ {title} ]" + content = f" {diamond} {stage} {diamond} " + + total_width = 90 + line_length = (total_width - len(content)) // 2 + line = "━" * line_length + divider = f"{line}{content}{line}" -def print_divider(title): - console.print(f"\n\n[bold magenta]{'-'*20} [ {title} ] {'-'*20}[/bold magenta]\n\n") + console.print("\n\n" + f"[bold bright_magenta]{divider}[/bold bright_magenta]\n\n") def extract_repo_name(repo_url: str) -> str: @@ -18,11 +26,12 @@ def print_summary(repo_url: str, detected_issues_count: int, output_dir: str, re print_divider("AutoFiC Summary") repo_name = extract_repo_name(repo_url) - console.print(f"✔️ [bold]Target Repository:[/bold] {repo_name}") - console.print(f"✔️ [bold]Files with detected vulnerabilities:[/bold] {detected_issues_count} files") - console.print(f"✔️ [bold]LLM Responses:[/bold] Saved in the 'llm' folder") + console.print(f"📦 [bold]Target Repository:[/bold] {repo_name}") + console.print() + console.print(f"🛡️ [bold]Files with detected vulnerabilities:[/bold] {detected_issues_count} files") + console.print() + console.print(f"🤖 [bold]LLM Responses:[/bold] Saved in the 'llm' folder") - console.print(f"\n[bold magenta]{'━'*64}[/bold magenta]\n") time.sleep(2.0) @@ -66,4 +75,3 @@ def print_help_message(): - The --patch option must be run before using --llm or --llm-retry options. - The --pr option must be run before using --patch option. """) - From 0d35cbd22443af3ee4798dd9f71ed0a86c919cdd Mon Sep 17 00:00:00 2001 From: soonnae Date: Sun, 27 Jul 2025 02:11:28 +0900 Subject: [PATCH 2/2] [AutoFiC] Fix --- .../llm/response_core_appHandler.js.md | 281 -------- .../downloaded_repo/llm/response_server.js.md | 70 -- .../downloaded_repo/parsed/core/appHandler.js | 254 ------- artifacts/downloaded_repo/parsed/server.js | 49 -- .../downloaded_repo/patch/appHandler.diff | 63 -- artifacts/downloaded_repo/patch/server.diff | 22 - artifacts/downloaded_repo/repo | 1 - artifacts/downloaded_repo/sast/before.json | 620 ------------------ .../downloaded_repo/sast/merged_snippets.json | 52 -- .../snippets/snippet_core_appHandler.js.json | 1 - .../snippets/snippet_server.js.json | 1 - 11 files changed, 1414 deletions(-) delete mode 100644 artifacts/downloaded_repo/llm/response_core_appHandler.js.md delete mode 100644 artifacts/downloaded_repo/llm/response_server.js.md delete mode 100644 artifacts/downloaded_repo/parsed/core/appHandler.js delete mode 100644 artifacts/downloaded_repo/parsed/server.js delete mode 100644 artifacts/downloaded_repo/patch/appHandler.diff delete mode 100644 artifacts/downloaded_repo/patch/server.diff delete mode 160000 artifacts/downloaded_repo/repo delete mode 100644 artifacts/downloaded_repo/sast/before.json delete mode 100644 artifacts/downloaded_repo/sast/merged_snippets.json delete mode 100644 artifacts/downloaded_repo/snippets/snippet_core_appHandler.js.json delete mode 100644 artifacts/downloaded_repo/snippets/snippet_server.js.json diff --git a/artifacts/downloaded_repo/llm/response_core_appHandler.js.md b/artifacts/downloaded_repo/llm/response_core_appHandler.js.md deleted file mode 100644 index 5352d3b..0000000 --- a/artifacts/downloaded_repo/llm/response_core_appHandler.js.md +++ /dev/null @@ -1,281 +0,0 @@ -1. 취약점 설명: - - SQL Injection: `userSearch` 함수에서 사용자 입력이 직접 SQL 쿼리에 포함되어 SQL 인젝션 공격에 취약합니다. - - Open Redirect: `redirect` 함수에서 사용자 입력을 통해 리다이렉트 URL이 결정되며, 이는 악의적인 사이트로의 리다이렉트에 악용될 수 있습니다. - - Insecure Deserialization: `bulkProductsLegacy` 함수에서 `serialize.unserialize`를 사용하여 사용자 입력을 역직렬화하고 있어 원격 코드 실행(RCE)에 취약합니다. - - XML Injection: `bulkProducts` 함수에서 `libxmljs`의 `noent` 옵션이 `true`로 설정되어 있어 XML 외부 엔티티(XXE) 공격에 취약합니다. - -2. 예상 위험: - - SQL Injection을 통해 데이터베이스가 손상되거나 민감한 정보가 유출될 수 있습니다. - - Open Redirect를 통해 사용자가 악의적인 사이트로 유도될 수 있습니다. - - Insecure Deserialization을 통해 원격 코드 실행이 발생할 수 있습니다. - - XML Injection을 통해 서버의 파일 시스템 접근 및 데이터 유출이 발생할 수 있습니다. - -3. 개선 방안: - - SQL Injection: 파라미터화된 쿼리를 사용하여 사용자 입력을 안전하게 처리합니다. - - Open Redirect: 허용된 URL 목록을 사용하여 리다이렉트 URL을 검증합니다. - - Insecure Deserialization: `serialize.unserialize` 대신 안전한 데이터 처리 방법을 사용합니다. - - XML Injection: `noent` 옵션을 `false`로 설정하여 XXE 공격을 방지합니다. - -4. 최종 수정된 전체 코드: -```javascript -var db = require('../models') -var bCrypt = require('bcrypt') -const exec = require('child_process').exec; -var mathjs = require('mathjs') -var libxmljs = require("libxmljs"); -var serialize = require("node-serialize") -const Op = db.Sequelize.Op - -module.exports.userSearch = function (req, res) { - var query = "SELECT name,id FROM Users WHERE login=:login"; - db.sequelize.query(query, { - replacements: { login: req.body.login }, - model: db.User - }).then(user => { - if (user.length) { - var output = { - user: { - name: user[0].name, - id: user[0].id - } - } - res.render('app/usersearch', { - output: output - }) - } else { - req.flash('warning', 'User not found') - res.render('app/usersearch', { - output: null - }) - } - }).catch(err => { - req.flash('danger', 'Internal Error') - res.render('app/usersearch', { - output: null - }) - }) -} - -module.exports.ping = function (req, res) { - exec('ping -c 2 ' + req.body.address, function (err, stdout, stderr) { - output = stdout + stderr - res.render('app/ping', { - output: output - }) - }) -} - -module.exports.listProducts = function (req, res) { - db.Product.findAll().then(products => { - output = { - products: products - } - res.render('app/products', { - output: output - }) - }) -} - -module.exports.productSearch = function (req, res) { - db.Product.findAll({ - where: { - name: { - [Op.like]: '%' + req.body.name + '%' - } - } - }).then(products => { - output = { - products: products, - searchTerm: req.body.name - } - res.render('app/products', { - output: output - }) - }) -} - -module.exports.modifyProduct = function (req, res) { - if (!req.query.id || req.query.id == '') { - output = { - product: {} - } - res.render('app/modifyproduct', { - output: output - }) - } else { - db.Product.find({ - where: { - 'id': req.query.id - } - }).then(product => { - if (!product) { - product = {} - } - output = { - product: product - } - res.render('app/modifyproduct', { - output: output - }) - }) - } -} - -module.exports.modifyProductSubmit = function (req, res) { - if (!req.body.id || req.body.id == '') { - req.body.id = 0 - } - db.Product.find({ - where: { - 'id': req.body.id - } - }).then(product => { - if (!product) { - product = new db.Product() - } - product.code = req.body.code - product.name = req.body.name - product.description = req.body.description - product.tags = req.body.tags - product.save().then(p => { - if (p) { - req.flash('success', 'Product added/modified!') - res.redirect('/app/products') - } - }).catch(err => { - output = { - product: product - } - req.flash('danger',err) - res.render('app/modifyproduct', { - output: output - }) - }) - }) -} - -module.exports.userEdit = function (req, res) { - res.render('app/useredit', { - userId: req.user.id, - userEmail: req.user.email, - userName: req.user.name - }) -} - -module.exports.userEditSubmit = function (req, res) { - db.User.find({ - where: { - 'id': req.body.id - } - }).then(user =>{ - if(req.body.password.length>0){ - if(req.body.password.length>0){ - if (req.body.password == req.body.cpassword) { - user.password = bCrypt.hashSync(req.body.password, bCrypt.genSaltSync(10), null) - }else{ - req.flash('warning', 'Passwords dont match') - res.render('app/useredit', { - userId: req.user.id, - userEmail: req.user.email, - userName: req.user.name, - }) - return - } - }else{ - req.flash('warning', 'Invalid Password') - res.render('app/useredit', { - userId: req.user.id, - userEmail: req.user.email, - userName: req.user.name, - }) - return - } - } - user.email = req.body.email - user.name = req.body.name - user.save().then(function () { - req.flash('success',"Updated successfully") - res.render('app/useredit', { - userId: req.body.id, - userEmail: req.body.email, - userName: req.body.name, - }) - }) - }) -} - -module.exports.redirect = function (req, res) { - const allowedUrls = ['https://trusted.com', 'https://another-trusted.com']; - if (req.query.url && allowedUrls.includes(req.query.url)) { - res.redirect(req.query.url) - } else { - res.send('invalid redirect url') - } -} - -module.exports.calc = function (req, res) { - if (req.body.eqn) { - res.render('app/calc', { - output: mathjs.eval(req.body.eqn) - }) - } else { - res.render('app/calc', { - output: 'Enter a valid math string like (3+3)*2' - }) - } -} - -module.exports.listUsersAPI = function (req, res) { - db.User.findAll({}).then(users => { - res.status(200).json({ - success: true, - users: users - }) - }) -} - -module.exports.bulkProductsLegacy = function (req,res){ - // TODO: Deprecate this soon - if(req.files.products){ - try { - var products = JSON.parse(req.files.products.data.toString('utf8')) - products.forEach( function (product) { - var newProduct = new db.Product() - newProduct.name = product.name - newProduct.code = product.code - newProduct.tags = product.tags - newProduct.description = product.description - newProduct.save() - }) - res.redirect('/app/products') - } catch (e) { - res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) - } - }else{ - res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) - } -} - -module.exports.bulkProducts = function(req, res) { - if (req.files.products && req.files.products.mimetype=='text/xml'){ - var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:false,noblanks:true}) - products.root().childNodes().forEach( product => { - var newProduct = new db.Product() - newProduct.name = product.childNodes()[0].text() - newProduct.code = product.childNodes()[1].text() - newProduct.tags = product.childNodes()[2].text() - newProduct.description = product.childNodes()[3].text() - newProduct.save() - }) - res.redirect('/app/products') - }else{ - res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:false}) - } -} -``` - -5. 참고사항: - - SQL Injection 방지를 위해 Sequelize의 `replacements` 옵션을 사용하여 파라미터화된 쿼리를 적용했습니다. - - Open Redirect 방지를 위해 허용된 URL 목록을 사용하여 검증을 추가했습니다. - - Insecure Deserialization 방지를 위해 `JSON.parse`를 사용하여 데이터를 안전하게 처리했습니다. - - XML Injection 방지를 위해 `libxmljs`의 `noent` 옵션을 `false`로 설정했습니다. \ No newline at end of file diff --git a/artifacts/downloaded_repo/llm/response_server.js.md b/artifacts/downloaded_repo/llm/response_server.js.md deleted file mode 100644 index 3b22516..0000000 --- a/artifacts/downloaded_repo/llm/response_server.js.md +++ /dev/null @@ -1,70 +0,0 @@ -1. 취약점 설명: - - 코드에서 세션 비밀 키가 하드코딩되어 있습니다. 이는 코드가 유출될 경우 비밀 키가 노출될 위험이 있습니다. - - 세션 설정에서 기본값을 사용하고 있으며, 이는 보안에 취약할 수 있습니다. 특히, `httpOnly`, `secure`, `domain`, `expires`, `path` 등의 속성이 설정되어 있지 않습니다. - -2. 예상 위험: - - 하드코딩된 비밀 키로 인해, 코드 유출 시 세션 탈취 등의 공격에 노출될 수 있습니다. - - 기본 세션 설정은 세션 하이재킹, XSS 공격 등에 취약할 수 있습니다. - -3. 개선 방안: - - 비밀 키는 환경 변수로 관리하여 코드에 직접 노출되지 않도록 합니다. - - 세션 설정에서 `httpOnly`, `secure`, `domain`, `expires`, `path` 등의 속성을 적절히 설정하여 보안을 강화합니다. - - 기본 세션 쿠키 이름을 변경하여 공격자가 서버를 식별하기 어렵게 합니다. - -4. 최종 수정된 전체 코드: -```javascript -var express = require('express') -var bodyParser = require('body-parser') -var passport = require('passport') -var session = require('express-session') -var ejs = require('ejs') -var morgan = require('morgan') -const fileUpload = require('express-fileupload'); -var config = require('./config/server') - -//Initialize Express -var app = express() -require('./core/passport')(passport) -app.use(express.static('public')) -app.set('view engine','ejs') -app.use(morgan('tiny')) -app.use(bodyParser.urlencoded({ extended: false })) -app.use(fileUpload()); - -// Enable for Reverse proxy support -// app.set('trust proxy', 1) - -// Intialize Session -app.use(session({ - secret: process.env.SESSION_SECRET || 'default_secret', - resave: true, - saveUninitialized: true, - name: 'session_id', - cookie: { - secure: process.env.NODE_ENV === 'production', - httpOnly: true, - domain: 'example.com', - expires: new Date(Date.now() + 60 * 60 * 1000), // 1 hour - path: '/' - } -})) - -// Initialize Passport -app.use(passport.initialize()) -app.use(passport.session()) - -// Initialize express-flash -app.use(require('express-flash')()); - -// Routing -app.use('/app',require('./routes/app')()) -app.use('/',require('./routes/main')(passport)) - -// Start Server -app.listen(config.port, config.listen) -``` - -5. 참고사항: - - `process.env.SESSION_SECRET` 환경 변수를 사용하여 비밀 키를 관리합니다. 환경 변수를 설정하지 않은 경우 `default_secret`을 사용하지만, 이는 개발 환경에서만 사용해야 합니다. - - `secure` 옵션은 `NODE_ENV`가 `production`일 때만 활성화되도록 설정하여, 개발 환경에서는 HTTPS가 필요하지 않도록 합니다. - - `domain` 및 `expires` 설정은 예시로 제공되었으며, 실제 환경에 맞게 조정해야 합니다. \ No newline at end of file diff --git a/artifacts/downloaded_repo/parsed/core/appHandler.js b/artifacts/downloaded_repo/parsed/core/appHandler.js deleted file mode 100644 index 482cde0..0000000 --- a/artifacts/downloaded_repo/parsed/core/appHandler.js +++ /dev/null @@ -1,254 +0,0 @@ -var db = require('../models') -var bCrypt = require('bcrypt') -const exec = require('child_process').exec; -var mathjs = require('mathjs') -var libxmljs = require("libxmljs"); -var serialize = require("node-serialize") -const Op = db.Sequelize.Op - -module.exports.userSearch = function (req, res) { - var query = "SELECT name,id FROM Users WHERE login=:login"; - db.sequelize.query(query, { - replacements: { login: req.body.login }, - model: db.User - }).then(user => { - if (user.length) { - var output = { - user: { - name: user[0].name, - id: user[0].id - } - } - res.render('app/usersearch', { - output: output - }) - } else { - req.flash('warning', 'User not found') - res.render('app/usersearch', { - output: null - }) - } - }).catch(err => { - req.flash('danger', 'Internal Error') - res.render('app/usersearch', { - output: null - }) - }) -} - -module.exports.ping = function (req, res) { - exec('ping -c 2 ' + req.body.address, function (err, stdout, stderr) { - output = stdout + stderr - res.render('app/ping', { - output: output - }) - }) -} - -module.exports.listProducts = function (req, res) { - db.Product.findAll().then(products => { - output = { - products: products - } - res.render('app/products', { - output: output - }) - }) -} - -module.exports.productSearch = function (req, res) { - db.Product.findAll({ - where: { - name: { - [Op.like]: '%' + req.body.name + '%' - } - } - }).then(products => { - output = { - products: products, - searchTerm: req.body.name - } - res.render('app/products', { - output: output - }) - }) -} - -module.exports.modifyProduct = function (req, res) { - if (!req.query.id || req.query.id == '') { - output = { - product: {} - } - res.render('app/modifyproduct', { - output: output - }) - } else { - db.Product.find({ - where: { - 'id': req.query.id - } - }).then(product => { - if (!product) { - product = {} - } - output = { - product: product - } - res.render('app/modifyproduct', { - output: output - }) - }) - } -} - -module.exports.modifyProductSubmit = function (req, res) { - if (!req.body.id || req.body.id == '') { - req.body.id = 0 - } - db.Product.find({ - where: { - 'id': req.body.id - } - }).then(product => { - if (!product) { - product = new db.Product() - } - product.code = req.body.code - product.name = req.body.name - product.description = req.body.description - product.tags = req.body.tags - product.save().then(p => { - if (p) { - req.flash('success', 'Product added/modified!') - res.redirect('/app/products') - } - }).catch(err => { - output = { - product: product - } - req.flash('danger',err) - res.render('app/modifyproduct', { - output: output - }) - }) - }) -} - -module.exports.userEdit = function (req, res) { - res.render('app/useredit', { - userId: req.user.id, - userEmail: req.user.email, - userName: req.user.name - }) -} - -module.exports.userEditSubmit = function (req, res) { - db.User.find({ - where: { - 'id': req.body.id - } - }).then(user =>{ - if(req.body.password.length>0){ - if(req.body.password.length>0){ - if (req.body.password == req.body.cpassword) { - user.password = bCrypt.hashSync(req.body.password, bCrypt.genSaltSync(10), null) - }else{ - req.flash('warning', 'Passwords dont match') - res.render('app/useredit', { - userId: req.user.id, - userEmail: req.user.email, - userName: req.user.name, - }) - return - } - }else{ - req.flash('warning', 'Invalid Password') - res.render('app/useredit', { - userId: req.user.id, - userEmail: req.user.email, - userName: req.user.name, - }) - return - } - } - user.email = req.body.email - user.name = req.body.name - user.save().then(function () { - req.flash('success',"Updated successfully") - res.render('app/useredit', { - userId: req.body.id, - userEmail: req.body.email, - userName: req.body.name, - }) - }) - }) -} - -module.exports.redirect = function (req, res) { - const allowedUrls = ['https://trusted.com', 'https://another-trusted.com']; - if (req.query.url && allowedUrls.includes(req.query.url)) { - res.redirect(req.query.url) - } else { - res.send('invalid redirect url') - } -} - -module.exports.calc = function (req, res) { - if (req.body.eqn) { - res.render('app/calc', { - output: mathjs.eval(req.body.eqn) - }) - } else { - res.render('app/calc', { - output: 'Enter a valid math string like (3+3)*2' - }) - } -} - -module.exports.listUsersAPI = function (req, res) { - db.User.findAll({}).then(users => { - res.status(200).json({ - success: true, - users: users - }) - }) -} - -module.exports.bulkProductsLegacy = function (req,res){ - // TODO: Deprecate this soon - if(req.files.products){ - try { - var products = JSON.parse(req.files.products.data.toString('utf8')) - products.forEach( function (product) { - var newProduct = new db.Product() - newProduct.name = product.name - newProduct.code = product.code - newProduct.tags = product.tags - newProduct.description = product.description - newProduct.save() - }) - res.redirect('/app/products') - } catch (e) { - res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) - } - }else{ - res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) - } -} - -module.exports.bulkProducts = function(req, res) { - if (req.files.products && req.files.products.mimetype=='text/xml'){ - var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:false,noblanks:true}) - products.root().childNodes().forEach( product => { - var newProduct = new db.Product() - newProduct.name = product.childNodes()[0].text() - newProduct.code = product.childNodes()[1].text() - newProduct.tags = product.childNodes()[2].text() - newProduct.description = product.childNodes()[3].text() - newProduct.save() - }) - res.redirect('/app/products') - }else{ - res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:false}) - } -} \ No newline at end of file diff --git a/artifacts/downloaded_repo/parsed/server.js b/artifacts/downloaded_repo/parsed/server.js deleted file mode 100644 index 0ad9f8a..0000000 --- a/artifacts/downloaded_repo/parsed/server.js +++ /dev/null @@ -1,49 +0,0 @@ -var express = require('express') -var bodyParser = require('body-parser') -var passport = require('passport') -var session = require('express-session') -var ejs = require('ejs') -var morgan = require('morgan') -const fileUpload = require('express-fileupload'); -var config = require('./config/server') - -//Initialize Express -var app = express() -require('./core/passport')(passport) -app.use(express.static('public')) -app.set('view engine','ejs') -app.use(morgan('tiny')) -app.use(bodyParser.urlencoded({ extended: false })) -app.use(fileUpload()); - -// Enable for Reverse proxy support -// app.set('trust proxy', 1) - -// Intialize Session -app.use(session({ - secret: process.env.SESSION_SECRET || 'default_secret', - resave: true, - saveUninitialized: true, - name: 'session_id', - cookie: { - secure: process.env.NODE_ENV === 'production', - httpOnly: true, - domain: 'example.com', - expires: new Date(Date.now() + 60 * 60 * 1000), // 1 hour - path: '/' - } -})) - -// Initialize Passport -app.use(passport.initialize()) -app.use(passport.session()) - -// Initialize express-flash -app.use(require('express-flash')()); - -// Routing -app.use('/app',require('./routes/app')()) -app.use('/',require('./routes/main')(passport)) - -// Start Server -app.listen(config.port, config.listen) \ No newline at end of file diff --git a/artifacts/downloaded_repo/patch/appHandler.diff b/artifacts/downloaded_repo/patch/appHandler.diff deleted file mode 100644 index 3d6325a..0000000 --- a/artifacts/downloaded_repo/patch/appHandler.diff +++ /dev/null @@ -1,63 +0,0 @@ ---- a/core/appHandler.js -+++ b/core/appHandler.js -@@ -7,8 +7,9 @@ - const Op = db.Sequelize.Op - - module.exports.userSearch = function (req, res) { -- var query = "SELECT name,id FROM Users WHERE login='" + req.body.login + "'"; -+ var query = "SELECT name,id FROM Users WHERE login=:login"; - db.sequelize.query(query, { -+ replacements: { login: req.body.login }, - model: db.User - }).then(user => { - if (user.length) { -@@ -184,7 +185,8 @@ - } - - module.exports.redirect = function (req, res) { -- if (req.query.url) { -+ const allowedUrls = ['https://trusted.com', 'https://another-trusted.com']; -+ if (req.query.url && allowedUrls.includes(req.query.url)) { - res.redirect(req.query.url) - } else { - res.send('invalid redirect url') -@@ -215,16 +217,20 @@ - module.exports.bulkProductsLegacy = function (req,res){ - // TODO: Deprecate this soon - if(req.files.products){ -- var products = serialize.unserialize(req.files.products.data.toString('utf8')) -- products.forEach( function (product) { -- var newProduct = new db.Product() -- newProduct.name = product.name -- newProduct.code = product.code -- newProduct.tags = product.tags -- newProduct.description = product.description -- newProduct.save() -- }) -- res.redirect('/app/products') -+ try { -+ var products = JSON.parse(req.files.products.data.toString('utf8')) -+ products.forEach( function (product) { -+ var newProduct = new db.Product() -+ newProduct.name = product.name -+ newProduct.code = product.code -+ newProduct.tags = product.tags -+ newProduct.description = product.description -+ newProduct.save() -+ }) -+ res.redirect('/app/products') -+ } catch (e) { -+ res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) -+ } - }else{ - res.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true}) - } -@@ -232,7 +238,7 @@ - - module.exports.bulkProducts = function(req, res) { - if (req.files.products && req.files.products.mimetype=='text/xml'){ -- var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true}) -+ var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:false,noblanks:true}) - products.root().childNodes().forEach( product => { - var newProduct = new db.Product() - newProduct.name = product.childNodes()[0].text() diff --git a/artifacts/downloaded_repo/patch/server.diff b/artifacts/downloaded_repo/patch/server.diff deleted file mode 100644 index e7617e8..0000000 --- a/artifacts/downloaded_repo/patch/server.diff +++ /dev/null @@ -1,22 +0,0 @@ ---- a/server.js -+++ b/server.js -@@ -21,10 +21,17 @@ - - // Intialize Session - app.use(session({ -- secret: 'keyboard cat', -+ secret: process.env.SESSION_SECRET || 'default_secret', - resave: true, - saveUninitialized: true, -- cookie: { secure: false } -+ name: 'session_id', -+ cookie: { -+ secure: process.env.NODE_ENV === 'production', -+ httpOnly: true, -+ domain: 'example.com', -+ expires: new Date(Date.now() + 60 * 60 * 1000), // 1 hour -+ path: '/' -+ } - })) - - // Initialize Passport diff --git a/artifacts/downloaded_repo/repo b/artifacts/downloaded_repo/repo deleted file mode 160000 index 9ba473a..0000000 --- a/artifacts/downloaded_repo/repo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9ba473add536f66ac9007966acb2a775dd31277a diff --git a/artifacts/downloaded_repo/sast/before.json b/artifacts/downloaded_repo/sast/before.json deleted file mode 100644 index cc0e134..0000000 --- a/artifacts/downloaded_repo/sast/before.json +++ /dev/null @@ -1,620 +0,0 @@ -{ - "version": "1.128.1", - "results": [ - { - "check_id": "javascript.sequelize.security.audit.sequelize-injection-express.express-sequelize-injection", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", - "start": { - "line": 11, - "col": 21, - "offset": 401 - }, - "end": { - "line": 11, - "col": 26, - "offset": 406 - }, - "extra": { - "message": "Detected a sequelize statement that is tainted by user-input. This could lead to SQL injection if the variable is user-controlled and is not properly sanitized. In order to prevent SQL injection, it is recommended to use parameterized queries or prepared statements.", - "metadata": { - "interfile": true, - "references": [ - "https://sequelize.org/docs/v6/core-concepts/raw-queries/#replacements" - ], - "category": "security", - "technology": [ - "express" - ], - "cwe": [ - "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')" - ], - "owasp": [ - "A01:2017 - Injection", - "A03:2021 - Injection" - ], - "cwe2022-top25": true, - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "HIGH", - "confidence": "HIGH", - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "SQL Injection" - ], - "source": "https://semgrep.dev/r/javascript.sequelize.security.audit.sequelize-injection-express.express-sequelize-injection", - "shortlink": "https://sg.run/gjoe" - }, - "severity": "ERROR", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-open-redirect.express-open-redirect", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", - "start": { - "line": 188, - "col": 16, - "offset": 4103 - }, - "end": { - "line": 188, - "col": 29, - "offset": 4116 - }, - "extra": { - "message": "The application redirects to a URL specified by user-supplied input `req` that is not validated. This could redirect users to malicious locations. Consider using an allow-list approach to validate URLs, or warn users they are being redirected to a third-party website.", - "metadata": { - "technology": [ - "express" - ], - "references": [ - "https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html" - ], - "cwe": [ - "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')" - ], - "category": "security", - "owasp": [ - "A01:2021 - Broken Access Control" - ], - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "MEDIUM", - "confidence": "HIGH", - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Open Redirect" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-open-redirect.express-open-redirect", - "shortlink": "https://sg.run/EpoP" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-third-party-object-deserialization.express-third-party-object-deserialization", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", - "start": { - "line": 218, - "col": 18, - "offset": 4721 - }, - "end": { - "line": 218, - "col": 81, - "offset": 4784 - }, - "extra": { - "message": "The following function call serialize.unserialize accepts user controlled data which can result in Remote Code Execution (RCE) through Object Deserialization. It is recommended to use secure data processing alternatives such as JSON.parse() and Buffer.from().", - "metadata": { - "interfile": true, - "technology": [ - "express" - ], - "category": "security", - "cwe": [ - "CWE-502: Deserialization of Untrusted Data" - ], - "references": [ - "https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html" - ], - "source_rule_url": [ - "https://github.com/ajinabraham/njsscan/blob/75bfbeb9c8d72999e4d527dfa2548f7f0f3cc48a/njsscan/rules/semantic_grep/eval/eval_deserialize.yaml" - ], - "owasp": [ - "A08:2017 - Insecure Deserialization", - "A08:2021 - Software and Data Integrity Failures" - ], - "cwe2022-top25": true, - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "HIGH", - "confidence": "HIGH", - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Insecure Deserialization " - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-third-party-object-deserialization.express-third-party-object-deserialization", - "shortlink": "https://sg.run/8W5j" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-libxml-noent.express-libxml-noent", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", - "start": { - "line": 235, - "col": 42, - "offset": 5344 - }, - "end": { - "line": 235, - "col": 82, - "offset": 5384 - }, - "extra": { - "message": "The libxml library processes user-input with the `noent` attribute is set to `true` which can lead to being vulnerable to XML External Entities (XXE) type attacks. It is recommended to set `noent` to `false` when using this feature to ensure you are protected.", - "metadata": { - "interfile": true, - "references": [ - "https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html" - ], - "technology": [ - "express" - ], - "category": "security", - "cwe": [ - "CWE-611: Improper Restriction of XML External Entity Reference" - ], - "owasp": [ - "A04:2017 - XML External Entities (XXE)", - "A05:2021 - Security Misconfiguration" - ], - "cwe2022-top25": true, - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "HIGH", - "confidence": "HIGH", - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "XML Injection" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-libxml-noent.express-libxml-noent", - "shortlink": "https://sg.run/Z75x" - }, - "severity": "ERROR", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-default-name", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", - "start": { - "line": 23, - "col": 9, - "offset": 655 - }, - "end": { - "line": 28, - "col": 3, - "offset": 769 - }, - "extra": { - "message": "Don’t use the default session cookie name Using the default session cookie name can open your app to attacks. The security issue posed is similar to X-Powered-By: a potential attacker can use it to fingerprint the server and target attacks accordingly.", - "metadata": { - "cwe": [ - "CWE-522: Insufficiently Protected Credentials" - ], - "owasp": [ - "A02:2017 - Broken Authentication", - "A04:2021 - Insecure Design" - ], - "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", - "category": "security", - "technology": [ - "express" - ], - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "LOW", - "confidence": "MEDIUM", - "references": [ - "https://owasp.org/Top10/A04_2021-Insecure_Design" - ], - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Cryptographic Issues" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-default-name", - "shortlink": "https://sg.run/1Z5x" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-domain", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", - "start": { - "line": 23, - "col": 9, - "offset": 655 - }, - "end": { - "line": 28, - "col": 3, - "offset": 769 - }, - "extra": { - "message": "Default session middleware settings: `domain` not set. It indicates the domain of the cookie; use it to compare against the domain of the server in which the URL is being requested. If they match, then check the path attribute next.", - "metadata": { - "cwe": [ - "CWE-522: Insufficiently Protected Credentials" - ], - "owasp": [ - "A02:2017 - Broken Authentication", - "A04:2021 - Insecure Design" - ], - "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", - "category": "security", - "technology": [ - "express" - ], - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "LOW", - "confidence": "MEDIUM", - "references": [ - "https://owasp.org/Top10/A04_2021-Insecure_Design" - ], - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Cryptographic Issues" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-domain", - "shortlink": "https://sg.run/rd41" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-expires", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", - "start": { - "line": 23, - "col": 9, - "offset": 655 - }, - "end": { - "line": 28, - "col": 3, - "offset": 769 - }, - "extra": { - "message": "Default session middleware settings: `expires` not set. Use it to set expiration date for persistent cookies.", - "metadata": { - "cwe": [ - "CWE-522: Insufficiently Protected Credentials" - ], - "owasp": [ - "A02:2017 - Broken Authentication", - "A04:2021 - Insecure Design" - ], - "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", - "category": "security", - "technology": [ - "express" - ], - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "LOW", - "confidence": "MEDIUM", - "references": [ - "https://owasp.org/Top10/A04_2021-Insecure_Design" - ], - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Cryptographic Issues" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-expires", - "shortlink": "https://sg.run/N4eG" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-httponly", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", - "start": { - "line": 23, - "col": 9, - "offset": 655 - }, - "end": { - "line": 28, - "col": 3, - "offset": 769 - }, - "extra": { - "message": "Default session middleware settings: `httpOnly` not set. It ensures the cookie is sent only over HTTP(S), not client JavaScript, helping to protect against cross-site scripting attacks.", - "metadata": { - "cwe": [ - "CWE-522: Insufficiently Protected Credentials" - ], - "owasp": [ - "A02:2017 - Broken Authentication", - "A04:2021 - Insecure Design" - ], - "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", - "category": "security", - "technology": [ - "express" - ], - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "LOW", - "confidence": "MEDIUM", - "references": [ - "https://owasp.org/Top10/A04_2021-Insecure_Design" - ], - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Cryptographic Issues" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-httponly", - "shortlink": "https://sg.run/ydBO" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-path", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", - "start": { - "line": 23, - "col": 9, - "offset": 655 - }, - "end": { - "line": 28, - "col": 3, - "offset": 769 - }, - "extra": { - "message": "Default session middleware settings: `path` not set. It indicates the path of the cookie; use it to compare against the request path. If this and domain match, then send the cookie in the request.", - "metadata": { - "cwe": [ - "CWE-522: Insufficiently Protected Credentials" - ], - "owasp": [ - "A02:2017 - Broken Authentication", - "A04:2021 - Insecure Design" - ], - "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", - "category": "security", - "technology": [ - "express" - ], - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "LOW", - "confidence": "MEDIUM", - "references": [ - "https://owasp.org/Top10/A04_2021-Insecure_Design" - ], - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Cryptographic Issues" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-path", - "shortlink": "https://sg.run/b7pd" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-secure", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", - "start": { - "line": 23, - "col": 9, - "offset": 655 - }, - "end": { - "line": 28, - "col": 3, - "offset": 769 - }, - "extra": { - "message": "Default session middleware settings: `secure` not set. It ensures the browser only sends the cookie over HTTPS.", - "metadata": { - "cwe": [ - "CWE-522: Insufficiently Protected Credentials" - ], - "owasp": [ - "A02:2017 - Broken Authentication", - "A04:2021 - Insecure Design" - ], - "source-rule-url": "https://expressjs.com/en/advanced/best-practice-security.html", - "category": "security", - "technology": [ - "express" - ], - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "LOW", - "confidence": "MEDIUM", - "references": [ - "https://owasp.org/Top10/A04_2021-Insecure_Design" - ], - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Cryptographic Issues" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-cookie-settings.express-cookie-session-no-secure", - "shortlink": "https://sg.run/9oKz" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - }, - { - "check_id": "javascript.express.security.audit.express-session-hardcoded-secret.express-session-hardcoded-secret", - "path": "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js", - "start": { - "line": 24, - "col": 3, - "offset": 668 - }, - "end": { - "line": 24, - "col": 25, - "offset": 690 - }, - "extra": { - "message": "A hard-coded credential was detected. It is not recommended to store credentials in source-code, as this risks secrets being leaked and used by either an internal or external malicious adversary. It is recommended to use environment variables to securely provide credentials or retrieve credentials from a secure vault or HSM (Hardware Security Module).", - "metadata": { - "interfile": true, - "cwe": [ - "CWE-798: Use of Hard-coded Credentials" - ], - "references": [ - "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" - ], - "owasp": [ - "A07:2021 - Identification and Authentication Failures" - ], - "category": "security", - "technology": [ - "express", - "secrets" - ], - "cwe2022-top25": true, - "cwe2021-top25": true, - "subcategory": [ - "vuln" - ], - "likelihood": "HIGH", - "impact": "HIGH", - "confidence": "HIGH", - "license": "Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license", - "vulnerability_class": [ - "Hard-coded Secrets" - ], - "source": "https://semgrep.dev/r/javascript.express.security.audit.express-session-hardcoded-secret.express-session-hardcoded-secret", - "shortlink": "https://sg.run/LYvG" - }, - "severity": "WARNING", - "fingerprint": "requires login", - "lines": "requires login", - "validation_state": "NO_VALIDATOR", - "engine_kind": "OSS" - } - } - ], - "errors": [], - "paths": { - "scanned": [ - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\config\\db.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\config\\server.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\config\\vulns.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\appHandler.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\authHandler.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\core\\passport.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\models\\index.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\models\\product.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\models\\user.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\routes\\app.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\routes\\main.js", - "C:\\Users\\ohjeo\\autofic-core\\artifacts\\downloaded_repo\\repo\\server.js" - ] - }, - "time": { - "rules": [], - "rules_parse_time": 0.4553208351135254, - "profiling_times": { - "config_time": 1.6937980651855469, - "core_time": 1.868072271347046, - "ignores_time": 0.0, - "total_time": 3.5632758140563965 - }, - "parsing_time": { - "total_time": 0.07409214973449707, - "per_file_time": { - "mean": 0.007409214973449707, - "std_dev": 8.423851878944789e-05 - }, - "very_slow_files": [] - }, - "targets": [], - "total_bytes": 0, - "max_memory_bytes": 188583296 - }, - "skipped_rules": [] -} \ No newline at end of file diff --git a/artifacts/downloaded_repo/sast/merged_snippets.json b/artifacts/downloaded_repo/sast/merged_snippets.json deleted file mode 100644 index a1126f0..0000000 --- a/artifacts/downloaded_repo/sast/merged_snippets.json +++ /dev/null @@ -1,52 +0,0 @@ -[ - { - "input": "var db = require('../models')\nvar bCrypt = require('bcrypt')\nconst exec = require('child_process').exec;\nvar mathjs = require('mathjs')\nvar libxmljs = require(\"libxmljs\");\nvar serialize = require(\"node-serialize\")\nconst Op = db.Sequelize.Op\n\nmodule.exports.userSearch = function (req, res) {\n\tvar query = \"SELECT name,id FROM Users WHERE login='\" + req.body.login + \"'\";\n\tdb.sequelize.query(query, {\n\t\tmodel: db.User\n\t}).then(user => {\n\t\tif (user.length) {\n\t\t\tvar output = {\n\t\t\t\tuser: {\n\t\t\t\t\tname: user[0].name,\n\t\t\t\t\tid: user[0].id\n\t\t\t\t}\n\t\t\t}\n\t\t\tres.render('app/usersearch', {\n\t\t\t\toutput: output\n\t\t\t})\n\t\t} else {\n\t\t\treq.flash('warning', 'User not found')\n\t\t\tres.render('app/usersearch', {\n\t\t\t\toutput: null\n\t\t\t})\n\t\t}\n\t}).catch(err => {\n\t\treq.flash('danger', 'Internal Error')\n\t\tres.render('app/usersearch', {\n\t\t\toutput: null\n\t\t})\n\t})\n}\n\nmodule.exports.ping = function (req, res) {\n\texec('ping -c 2 ' + req.body.address, function (err, stdout, stderr) {\n\t\toutput = stdout + stderr\n\t\tres.render('app/ping', {\n\t\t\toutput: output\n\t\t})\n\t})\n}\n\nmodule.exports.listProducts = function (req, res) {\n\tdb.Product.findAll().then(products => {\n\t\toutput = {\n\t\t\tproducts: products\n\t\t}\n\t\tres.render('app/products', {\n\t\t\toutput: output\n\t\t})\n\t})\n}\n\nmodule.exports.productSearch = function (req, res) {\n\tdb.Product.findAll({\n\t\twhere: {\n\t\t\tname: {\n\t\t\t\t[Op.like]: '%' + req.body.name + '%'\n\t\t\t}\n\t\t}\n\t}).then(products => {\n\t\toutput = {\n\t\t\tproducts: products,\n\t\t\tsearchTerm: req.body.name\n\t\t}\n\t\tres.render('app/products', {\n\t\t\toutput: output\n\t\t})\n\t})\n}\n\nmodule.exports.modifyProduct = function (req, res) {\n\tif (!req.query.id || req.query.id == '') {\n\t\toutput = {\n\t\t\tproduct: {}\n\t\t}\n\t\tres.render('app/modifyproduct', {\n\t\t\toutput: output\n\t\t})\n\t} else {\n\t\tdb.Product.find({\n\t\t\twhere: {\n\t\t\t\t'id': req.query.id\n\t\t\t}\n\t\t}).then(product => {\n\t\t\tif (!product) {\n\t\t\t\tproduct = {}\n\t\t\t}\n\t\t\toutput = {\n\t\t\t\tproduct: product\n\t\t\t}\n\t\t\tres.render('app/modifyproduct', {\n\t\t\t\toutput: output\n\t\t\t})\n\t\t})\n\t}\n}\n\nmodule.exports.modifyProductSubmit = function (req, res) {\n\tif (!req.body.id || req.body.id == '') {\n\t\treq.body.id = 0\n\t}\n\tdb.Product.find({\n\t\twhere: {\n\t\t\t'id': req.body.id\n\t\t}\n\t}).then(product => {\n\t\tif (!product) {\n\t\t\tproduct = new db.Product()\n\t\t}\n\t\tproduct.code = req.body.code\n\t\tproduct.name = req.body.name\n\t\tproduct.description = req.body.description\n\t\tproduct.tags = req.body.tags\n\t\tproduct.save().then(p => {\n\t\t\tif (p) {\n\t\t\t\treq.flash('success', 'Product added/modified!')\n\t\t\t\tres.redirect('/app/products')\n\t\t\t}\n\t\t}).catch(err => {\n\t\t\toutput = {\n\t\t\t\tproduct: product\n\t\t\t}\n\t\t\treq.flash('danger',err)\n\t\t\tres.render('app/modifyproduct', {\n\t\t\t\toutput: output\n\t\t\t})\n\t\t})\n\t})\n}\n\nmodule.exports.userEdit = function (req, res) {\n\tres.render('app/useredit', {\n\t\tuserId: req.user.id,\n\t\tuserEmail: req.user.email,\n\t\tuserName: req.user.name\n\t})\n}\n\nmodule.exports.userEditSubmit = function (req, res) {\n\tdb.User.find({\n\t\twhere: {\n\t\t\t'id': req.body.id\n\t\t}\t\t\n\t}).then(user =>{\n\t\tif(req.body.password.length>0){\n\t\t\tif(req.body.password.length>0){\n\t\t\t\tif (req.body.password == req.body.cpassword) {\n\t\t\t\t\tuser.password = bCrypt.hashSync(req.body.password, bCrypt.genSaltSync(10), null)\n\t\t\t\t}else{\n\t\t\t\t\treq.flash('warning', 'Passwords dont match')\n\t\t\t\t\tres.render('app/useredit', {\n\t\t\t\t\t\tuserId: req.user.id,\n\t\t\t\t\t\tuserEmail: req.user.email,\n\t\t\t\t\t\tuserName: req.user.name,\n\t\t\t\t\t})\n\t\t\t\t\treturn\t\t\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\treq.flash('warning', 'Invalid Password')\n\t\t\t\tres.render('app/useredit', {\n\t\t\t\t\tuserId: req.user.id,\n\t\t\t\t\tuserEmail: req.user.email,\n\t\t\t\t\tuserName: req.user.name,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tuser.email = req.body.email\n\t\tuser.name = req.body.name\n\t\tuser.save().then(function () {\n\t\t\treq.flash('success',\"Updated successfully\")\n\t\t\tres.render('app/useredit', {\n\t\t\t\tuserId: req.body.id,\n\t\t\t\tuserEmail: req.body.email,\n\t\t\t\tuserName: req.body.name,\n\t\t\t})\n\t\t})\n\t})\n}\n\nmodule.exports.redirect = function (req, res) {\n\tif (req.query.url) {\n\t\tres.redirect(req.query.url)\n\t} else {\n\t\tres.send('invalid redirect url')\n\t}\n}\n\nmodule.exports.calc = function (req, res) {\n\tif (req.body.eqn) {\n\t\tres.render('app/calc', {\n\t\t\toutput: mathjs.eval(req.body.eqn)\n\t\t})\n\t} else {\n\t\tres.render('app/calc', {\n\t\t\toutput: 'Enter a valid math string like (3+3)*2'\n\t\t})\n\t}\n}\n\nmodule.exports.listUsersAPI = function (req, res) {\n\tdb.User.findAll({}).then(users => {\n\t\tres.status(200).json({\n\t\t\tsuccess: true,\n\t\t\tusers: users\n\t\t})\n\t})\n}\n\nmodule.exports.bulkProductsLegacy = function (req,res){\n\t// TODO: Deprecate this soon\n\tif(req.files.products){\n\t\tvar products = serialize.unserialize(req.files.products.data.toString('utf8'))\n\t\tproducts.forEach( function (product) {\n\t\t\tvar newProduct = new db.Product()\n\t\t\tnewProduct.name = product.name\n\t\t\tnewProduct.code = product.code\n\t\t\tnewProduct.tags = product.tags\n\t\t\tnewProduct.description = product.description\n\t\t\tnewProduct.save()\n\t\t})\n\t\tres.redirect('/app/products')\n\t}else{\n\t\tres.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:true})\n\t}\n}\n\nmodule.exports.bulkProducts = function(req, res) {\n\tif (req.files.products && req.files.products.mimetype=='text/xml'){\n\t\tvar products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true})\n\t\tproducts.root().childNodes().forEach( product => {\n\t\t\tvar newProduct = new db.Product()\n\t\t\tnewProduct.name = product.childNodes()[0].text()\n\t\t\tnewProduct.code = product.childNodes()[1].text()\n\t\t\tnewProduct.tags = product.childNodes()[2].text()\n\t\t\tnewProduct.description = product.childNodes()[3].text()\n\t\t\tnewProduct.save()\n\t\t})\n\t\tres.redirect('/app/products')\n\t}else{\n\t\tres.render('app/bulkproducts',{messages:{danger:'Invalid file'},legacy:false})\n\t}\n}\n", - "idx": null, - "start_line": 11, - "end_line": 235, - "snippet": "\t\tres.redirect(req.query.url)\n\t\tvar products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true})\n\t\tvar products = serialize.unserialize(req.files.products.data.toString('utf8'))\n\tdb.sequelize.query(query, {", - "message": "Detected a sequelize statement that is tainted by user-input. This could lead to SQL injection if the variable is user-controlled and is not properly sanitized. In order to prevent SQL injection, it is recommended to use parameterized queries or prepared statements. | The application redirects to a URL specified by user-supplied input `req` that is not validated. This could redirect users to malicious locations. Consider using an allow-list approach to validate URLs, or warn users they are being redirected to a third-party website. | The following function call serialize.unserialize accepts user controlled data which can result in Remote Code Execution (RCE) through Object Deserialization. It is recommended to use secure data processing alternatives such as JSON.parse() and Buffer.from(). | The libxml library processes user-input with the `noent` attribute is set to `true` which can lead to being vulnerable to XML External Entities (XXE) type attacks. It is recommended to set `noent` to `false` when using this feature to ensure you are protected.", - "vulnerability_class": [ - "Insecure Deserialization ", - "Open Redirect", - "SQL Injection", - "XML Injection" - ], - "cwe": [ - "CWE-502: Deserialization of Untrusted Data", - "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')", - "CWE-611: Improper Restriction of XML External Entity Reference", - "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')" - ], - "severity": "ERROR", - "references": [ - "https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html", - "https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html", - "https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html", - "https://sequelize.org/docs/v6/core-concepts/raw-queries/#replacements" - ], - "path": "core/appHandler.js" - }, - { - "input": "var express = require('express')\nvar bodyParser = require('body-parser')\nvar passport = require('passport')\nvar session = require('express-session')\nvar ejs = require('ejs')\nvar morgan = require('morgan')\nconst fileUpload = require('express-fileupload');\nvar config = require('./config/server')\n\n//Initialize Express\nvar app = express()\nrequire('./core/passport')(passport)\napp.use(express.static('public'))\napp.set('view engine','ejs')\napp.use(morgan('tiny'))\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(fileUpload());\n\n// Enable for Reverse proxy support\n// app.set('trust proxy', 1) \n\n// Intialize Session\napp.use(session({\n secret: 'keyboard cat',\n resave: true,\n saveUninitialized: true,\n cookie: { secure: false }\n}))\n\n// Initialize Passport\napp.use(passport.initialize())\napp.use(passport.session())\n\n// Initialize express-flash\napp.use(require('express-flash')());\n\n// Routing\napp.use('/app',require('./routes/app')())\napp.use('/',require('./routes/main')(passport))\n\n// Start Server\napp.listen(config.port, config.listen)", - "idx": null, - "start_line": 23, - "end_line": 28, - "snippet": " cookie: { secure: false }\n resave: true,\n saveUninitialized: true,\n secret: 'keyboard cat',\napp.use(session({\n}))", - "message": "A hard-coded credential was detected. It is not recommended to store credentials in source-code, as this risks secrets being leaked and used by either an internal or external malicious adversary. It is recommended to use environment variables to securely provide credentials or retrieve credentials from a secure vault or HSM (Hardware Security Module). | Default session middleware settings: `domain` not set. It indicates the domain of the cookie; use it to compare against the domain of the server in which the URL is being requested. If they match, then check the path attribute next. | Default session middleware settings: `expires` not set. Use it to set expiration date for persistent cookies. | Default session middleware settings: `httpOnly` not set. It ensures the cookie is sent only over HTTP(S), not client JavaScript, helping to protect against cross-site scripting attacks. | Default session middleware settings: `path` not set. It indicates the path of the cookie; use it to compare against the request path. If this and domain match, then send the cookie in the request. | Default session middleware settings: `secure` not set. It ensures the browser only sends the cookie over HTTPS. | Don’t use the default session cookie name Using the default session cookie name can open your app to attacks. The security issue posed is similar to X-Powered-By: a potential attacker can use it to fingerprint the server and target attacks accordingly.", - "vulnerability_class": [ - "Cryptographic Issues", - "Hard-coded Secrets" - ], - "cwe": [ - "CWE-522: Insufficiently Protected Credentials", - "CWE-798: Use of Hard-coded Credentials" - ], - "severity": "WARNING", - "references": [ - "https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html", - "https://owasp.org/Top10/A04_2021-Insecure_Design" - ], - "path": "server.js" - } -] \ No newline at end of file diff --git a/artifacts/downloaded_repo/snippets/snippet_core_appHandler.js.json b/artifacts/downloaded_repo/snippets/snippet_core_appHandler.js.json deleted file mode 100644 index 1451021..0000000 --- a/artifacts/downloaded_repo/snippets/snippet_core_appHandler.js.json +++ /dev/null @@ -1 +0,0 @@ -"\t\tres.redirect(req.query.url)\n\t\tvar products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true})\n\t\tvar products = serialize.unserialize(req.files.products.data.toString('utf8'))\n\tdb.sequelize.query(query, {" \ No newline at end of file diff --git a/artifacts/downloaded_repo/snippets/snippet_server.js.json b/artifacts/downloaded_repo/snippets/snippet_server.js.json deleted file mode 100644 index 8a0d1c0..0000000 --- a/artifacts/downloaded_repo/snippets/snippet_server.js.json +++ /dev/null @@ -1 +0,0 @@ -" cookie: { secure: false }\n resave: true,\n saveUninitialized: true,\n secret: 'keyboard cat',\napp.use(session({\n}))" \ No newline at end of file