From b5584517105a7e149311f3adf046c51e0289edc8 Mon Sep 17 00:00:00 2001 From: Sandor Trombitas Date: Tue, 26 Nov 2024 09:50:12 +0200 Subject: [PATCH] feat: support severity change overrides in golang snyk code test --- cliv2/go.mod | 6 +- cliv2/go.sum | 12 +- .../fixtures/test-sarif-no-null-fields.json | 3117 +++++++++++++++++ .../snyk-code/fixtures/test-sarif.json | 7 + .../acceptance/snyk-code/snyk-code.spec.ts | 41 +- test/jest/util/sortSarif.ts | 11 + 6 files changed, 3181 insertions(+), 13 deletions(-) create mode 100644 test/jest/acceptance/snyk-code/fixtures/test-sarif-no-null-fields.json create mode 100644 test/jest/util/sortSarif.ts diff --git a/cliv2/go.mod b/cliv2/go.mod index 8889bb73e0..5bf8cb1f33 100644 --- a/cliv2/go.mod +++ b/cliv2/go.mod @@ -17,7 +17,7 @@ require ( github.com/snyk/cli-extension-sbom v0.0.0-20241016065306-0df2be5b3b8f github.com/snyk/container-cli v0.0.0-20240821111304-7ca1c415a5d7 github.com/snyk/error-catalog-golang-public v0.0.0-20241030160523-0aa643bb7069 - github.com/snyk/go-application-framework v0.0.0-20241202122446-a1ff367a586f + github.com/snyk/go-application-framework v0.0.0-20241203171103-86c8bdced10d github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65 github.com/snyk/snyk-iac-capture v0.6.5 github.com/snyk/snyk-ls v0.0.0-20241128161444-157e462bd309 @@ -38,7 +38,7 @@ require ( dario.cat/mergo v1.0.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect - github.com/ProtonMail/go-crypto v1.1.2 // indirect + github.com/ProtonMail/go-crypto v1.1.3 // indirect github.com/adrg/strutil v0.3.1 // indirect github.com/adrg/xdg v0.5.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect @@ -164,7 +164,7 @@ require ( github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/skeema/knownhosts v1.3.0 // indirect - github.com/snyk/code-client-go v1.10.0 // indirect + github.com/snyk/code-client-go v1.11.1 // indirect github.com/snyk/policy-engine v0.31.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/go-lsp v0.0.0-20240223163137-f80c5dd31dfd // indirect diff --git a/cliv2/go.sum b/cliv2/go.sum index 0c5a84df54..dedc352c4c 100644 --- a/cliv2/go.sum +++ b/cliv2/go.sum @@ -203,8 +203,8 @@ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/ProtonMail/go-crypto v1.1.2 h1:A7JbD57ThNqh7XjmHE+PXpQ3Dqt3BrSAC0AL0Go3KS0= -github.com/ProtonMail/go-crypto v1.1.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= +github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/adrg/strutil v0.3.1 h1:OLvSS7CSJO8lBii4YmBt8jiK9QOtB9CzCzwl4Ic/Fz4= github.com/adrg/strutil v0.3.1/go.mod h1:8h90y18QLrs11IBffcGX3NW/GFBXCMcNg4M7H6MspPA= @@ -754,14 +754,14 @@ github.com/snyk/cli-extension-iac-rules v0.0.0-20241008152401-24c8cf03a1a3 h1:AQ github.com/snyk/cli-extension-iac-rules v0.0.0-20241008152401-24c8cf03a1a3/go.mod h1:A/DNK3ZnUgqOKJ33Lc1z5KbbHqRSBgwCWw9KuyJu0xQ= github.com/snyk/cli-extension-sbom v0.0.0-20241016065306-0df2be5b3b8f h1:dlL+f+5sjHj4JCzW/Evl1x9UREXLyc3M4KjoZvQx0Bs= github.com/snyk/cli-extension-sbom v0.0.0-20241016065306-0df2be5b3b8f/go.mod h1:5CaY1bgvJY/uoG/1plLOf8T8o9AkwoBIGvw34RfRLZw= -github.com/snyk/code-client-go v1.10.0 h1:t/hBINxj4lKvoo681uGhxHBpMued/j68p2sHbB9qbfo= -github.com/snyk/code-client-go v1.10.0/go.mod h1:orU911flV1kJQOlxxx0InUQkAfpBrcERsb2olfnlI8s= +github.com/snyk/code-client-go v1.11.1 h1:k3dwlcMDNKEnML82OeZVXmt5p/YIkGFAs8usbSh4WHw= +github.com/snyk/code-client-go v1.11.1/go.mod h1:orU911flV1kJQOlxxx0InUQkAfpBrcERsb2olfnlI8s= github.com/snyk/container-cli v0.0.0-20240821111304-7ca1c415a5d7 h1:Zn5BcV76oFAbJm5tDygU945lvoZ3yY8FoRFDC3YpwF8= github.com/snyk/container-cli v0.0.0-20240821111304-7ca1c415a5d7/go.mod h1:38w+dcAQp9eG3P5t2eNS9eG0reut10AeJjLv5lJ5lpM= github.com/snyk/error-catalog-golang-public v0.0.0-20241030160523-0aa643bb7069 h1:Oj/BJAEMEuBjTAQ72UYB4tR0IZKOB2ZtdDnAnJDL1BM= github.com/snyk/error-catalog-golang-public v0.0.0-20241030160523-0aa643bb7069/go.mod h1:Ytttq7Pw4vOCu9NtRQaOeDU2dhBYUyNBe6kX4+nIIQ4= -github.com/snyk/go-application-framework v0.0.0-20241202122446-a1ff367a586f h1:eNu5W0dQaRuD4epXxEtwE+CZvY/fgX62RkPfQsv2V/c= -github.com/snyk/go-application-framework v0.0.0-20241202122446-a1ff367a586f/go.mod h1:GekIT38VeZQiDw/Ot9Qn0s2kxVR1TXMw6gcaaAiKsVg= +github.com/snyk/go-application-framework v0.0.0-20241203171103-86c8bdced10d h1:VfNH4vKxUfy4EGgZMkO38CBP/SybD61SjLFeWNNUAnY= +github.com/snyk/go-application-framework v0.0.0-20241203171103-86c8bdced10d/go.mod h1:BCtCRtpXHdzZYBQYL3XKXJFz/20IkqHat9oT9tY4U9U= github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65 h1:CEQuYv0Go6MEyRCD3YjLYM2u3Oxkx8GpCpFBd4rUTUk= github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65/go.mod h1:88KbbvGYlmLgee4OcQ19yr0bNpXpOr2kciOthaSzCAg= github.com/snyk/policy-engine v0.31.3 h1:FepCg6QN/X8uvxYjF+WwB2aiBPJB+NENDgKQeI/FwLg= diff --git a/test/jest/acceptance/snyk-code/fixtures/test-sarif-no-null-fields.json b/test/jest/acceptance/snyk-code/fixtures/test-sarif-no-null-fields.json new file mode 100644 index 0000000000..f82beb0fab --- /dev/null +++ b/test/jest/acceptance/snyk-code/fixtures/test-sarif-no-null-fields.json @@ -0,0 +1,3117 @@ +{ + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/schemas/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "snyk-cli", + "informationUri": "https://docs.snyk.io/", + "semanticVersion": "1.0.0", + "version": "1.0.0", + "rules": [ + { + "id": "javascript/NoRateLimitingForExpensiveWebOperation", + "name": "NoRateLimitingForExpensiveWebOperation", + "shortDescription": { + "text": "Allocation of Resources Without Limits or Throttling" + }, + "defaultConfiguration": { + "level": "warning" + }, + "help": { + "markdown": "\n## Details\n\nWithout unlimited resources, software operating in the real world is inherently limited in the resources it may consume; similarly, servers are limited by the number of simultaneous sessions they can handle. Therefore, it is important for developers to design software that considers these real-world physical (or virtual) limitations and limits user sessions accordingly, both in terms of the number of user sessions and in the quantity of resources each user may demand. Software with this weakness does not include such limitations and as a result, individual user sessions may consume too many resources, leading to unintended software behavior including, potentially, denial of service. This can be compared to a single restaurant customer emptying out the entire buffet, leaving no food for other customers--or an entire busload mobbing the buffet all at once, with a similar effect. This may happen inadvertently or as a result of an attack by a malicious user.\n\n## Best practices for prevention\n* Test extensively to obtain baseline values indicating how the software performs in the real world under various conditions (normal and peak); use these values to determine reasonable software limits.\n* Set clear limits for all flexible parameters such as maximum allocable memory, number of processes within a given timeframe, file descriptors, requests per client, number of records per request, etc. This is particularly true for any parameters within user control.\n* Release all resources when no longer in use, including incorporating timeouts for inactive users, processes, and resources.\n* Familiarize Dev, Ops, and IT teams with best practices for recognizing and preventing DoS attacks and out-of-control resource allocation to prevent catastrophic failures.", + "text": "something" + }, + "properties": { + "tags": [ + "javascript", + "NoRateLimitingForExpensiveWebOperation", + "Security" + ], + "categories": ["Security"], + "exampleCommitFixes": [ + { + "commitURL": "https://github.com/natsukagami/themis-web-interface/commit/e1ef34f8b95e7eefab54c204b78fbdee70169a6d?diff=split#diff-cd0e12b228a7dea99a7346adf68cfc7a6a2c321846cc8a90fc6cd92cf8066d5eL-1", + "lines": [ + { + "line": "router.post('/', (req, res, next) =\u003e {\n", + "lineNumber": 8, + "lineChange": "removed" + }, + { + "line": "const rateLimiter = require('../controls/rate-limiter')({\n", + "lineNumber": 8, + "lineChange": "added" + }, + { + "line": "\t// Allow 3 submits, then slows down\n", + "lineNumber": 9, + "lineChange": "added" + }, + { + "line": "\tfreeRetries: 30,\n", + "lineNumber": 10, + "lineChange": "added" + }, + { + "line": "\tminWait: 2 * 60 * 60,\n", + "lineNumber": 11, + "lineChange": "added" + }, + { + "line": "\tmaxWait: 2 * 60 * 60,\n", + "lineNumber": 12, + "lineChange": "added" + }, + { + "line": "\tlifetime: 60 * 60\n", + "lineNumber": 13, + "lineChange": "added" + }, + { + "line": "});\n", + "lineNumber": 14, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 15, + "lineChange": "added" + }, + { + "line": "router.post('/', rateLimiter.prevent, (req, res, next) =\u003e {\n", + "lineNumber": 16, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/Waifu-pics/waifu-api/commit/da0d3b4ee8dd4e2ab0a789dfd04cb304a537368e?diff=split#diff-0eddd48e85f4f98a238d49bfe0b4cf514b1430322bcdc196b1a97786e0ec30c8L-1", + "lines": [ + { + "line": "const rateLimit = require(\"express-rate-limit\")\n", + "lineNumber": 4, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 5, + "lineChange": "none" + }, + { + "line": "module.exports = ({ db, app, config, s3 }) =\u003e {\n", + "lineNumber": 6, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 7, + "lineChange": "added" + }, + { + "line": " // Checking if user is Admin to prevent rate limit middleware\n", + "lineNumber": 8, + "lineChange": "added" + }, + { + "line": " const chkAdmin = async (req, res, next) =\u003e {\n", + "lineNumber": 9, + "lineChange": "added" + }, + { + "line": " const { token } = req.headers\n", + "lineNumber": 10, + "lineChange": "added" + }, + { + "line": " const Admins = db.collection('admins')\n", + "lineNumber": 11, + "lineChange": "added" + }, + { + "line": " req.chkAdmin = Boolean(req.headers.token \u0026\u0026 typeof token === \"string\" \u0026\u0026 Boolean(await Admins.findOne({token})))\n", + "lineNumber": 12, + "lineChange": "added" + }, + { + "line": " \n", + "lineNumber": 13, + "lineChange": "added" + }, + { + "line": " next()\n", + "lineNumber": 14, + "lineChange": "added" + }, + { + "line": " }\n", + "lineNumber": 15, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 16, + "lineChange": "added" + }, + { + "line": " // Rate limit middleware\n", + "lineNumber": 17, + "lineChange": "added" + }, + { + "line": " const limiter = rateLimit({\n", + "lineNumber": 18, + "lineChange": "added" + }, + { + "line": " windowMs: 10 * 60 * 1000, // 10 minutes\n", + "lineNumber": 19, + "lineChange": "added" + }, + { + "line": " max: 15,\n", + "lineNumber": 20, + "lineChange": "added" + }, + { + "line": " message: \"You can only upload 15 files per 10 minutes!\",\n", + "lineNumber": 21, + "lineChange": "added" + }, + { + "line": " statusCode: 400,\n", + "lineNumber": 22, + "lineChange": "added" + }, + { + "line": " skip: function (req) {\n", + "lineNumber": 23, + "lineChange": "added" + }, + { + "line": " return req.chkAdmin\n", + "lineNumber": 24, + "lineChange": "added" + }, + { + "line": " }\n", + "lineNumber": 25, + "lineChange": "added" + }, + { + "line": " })\n", + "lineNumber": 26, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 27, + "lineChange": "added" + }, + { + "line": " // Do shit to upload\n", + "lineNumber": 28, + "lineChange": "added" + }, + { + "line": " app.use(\"/api/upload\", chkAdmin, limiter)\n", + "lineNumber": 29, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 30, + "lineChange": "added" + }, + { + "line": " app.use(fileUpload({\n", + "lineNumber": 31, + "lineChange": "none" + }, + { + "line": " limits: { fileSize: config.maxUploadSize * 1024 * 1024 },\n", + "lineNumber": 32, + "lineChange": "none" + }, + { + "line": " abortOnLimit: true,\n", + "lineNumber": 33, + "lineChange": "none" + }, + { + "line": " createParentPath: true\n", + "lineNumber": 34, + "lineChange": "none" + }, + { + "line": " }))\n", + "lineNumber": 35, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 36, + "lineChange": "none" + }, + { + "line": " app.post('/api/upload', async (req, res) =\u003e {\n", + "lineNumber": 37, + "lineChange": "none" + } + ] + }, + { + "commitURL": "https://github.com/davidmerfield/Blot/commit/f2bcb51b129075c8ebe5c1c23fac36dee35e800c?diff=split#diff-31b7f0d966974821a84da24ef72a8b290d5b82d34861dbdf7be2743821b2f4f5L-1", + "lines": [ + { + "line": "// stores state locally, don't use this in production\n", + "lineNumber": 10, + "lineChange": "removed" + }, + { + "line": "// var brute = require('express-brute');\n", + "lineNumber": 11, + "lineChange": "removed" + }, + { + "line": "// var store = new brute.MemoryStore();\n", + "lineNumber": 12, + "lineChange": "removed" + }, + { + "line": "// var limiter = new brute(store);\n", + "lineNumber": 13, + "lineChange": "removed" + }, + { + "line": "var client = require('client');\n", + "lineNumber": 10, + "lineChange": "added" + }, + { + "line": "var Brute = require('express-brute');\n", + "lineNumber": 11, + "lineChange": "added" + }, + { + "line": "var RedisStore = require('express-brute-redis');\n", + "lineNumber": 12, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 13, + "lineChange": "added" + }, + { + "line": "var store = new RedisStore({\n", + "lineNumber": 14, + "lineChange": "added" + }, + { + "line": " client: client,\n", + "lineNumber": 15, + "lineChange": "added" + }, + { + "line": " prefix: 'brute:'\n", + "lineNumber": 16, + "lineChange": "added" + }, + { + "line": "});\n", + "lineNumber": 17, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 18, + "lineChange": "added" + }, + { + "line": "var limiter = new Brute(store, {\n", + "lineNumber": 19, + "lineChange": "added" + }, + { + "line": " freeRetries: 200,\n", + "lineNumber": 20, + "lineChange": "added" + }, + { + "line": " failCallback: onLimit,\n", + "lineNumber": 21, + "lineChange": "added" + }, + { + "line": "});\n", + "lineNumber": 22, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 23, + "lineChange": "none" + }, + { + "line": "var login = Express.Router();\n", + "lineNumber": 24, + "lineChange": "none" + }, + { + "line": "var form = login.route('/');\n", + "lineNumber": 25, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 26, + "lineChange": "none" + }, + { + "line": "form.all(limiter.prevent);\n", + "lineNumber": 27, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 28, + "lineChange": "added" + }, + { + "line": "form.get(checkToken, function(req, res){\n", + "lineNumber": 29, + "lineChange": "none" + }, + { + "line": " res.render('log-in-email');\n", + "lineNumber": 30, + "lineChange": "none" + }, + { + "line": "});\n", + "lineNumber": 31, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 32, + "lineChange": "none" + }, + { + "line": "form.post(parse, checkEmail, checkReset, checkPassword);\n", + "lineNumber": 33, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 34, + "lineChange": "none" + }, + { + "line": "form.all(errorHandler);\n", + "lineNumber": 35, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 36, + "lineChange": "none" + }, + { + "line": "function onLimit (req, res, next, until) {\n", + "lineNumber": 37, + "lineChange": "added" + }, + { + "line": " res.status(429).send('Log in rate limit hit. Please wait ' + moment(until).toNow(true) + ' before retrying.');\n", + "lineNumber": 38, + "lineChange": "added" + }, + { + "line": "}\n", + "lineNumber": 39, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 40, + "lineChange": "added" + } + ] + } + ], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 27, + "cwe": ["CWE-770"] + } + }, + { + "id": "javascript/NoSqli", + "name": "NoSqli", + "shortDescription": { + "text": "NoSQL Injection" + }, + "defaultConfiguration": { + "level": "error" + }, + "help": { + "markdown": "## Details\n\nIn an NoSQL injection attack, the user can submit an NoSQL query directly to the database, gaining access without providing appropriate credentials. Attackers can then view, export, modify, and delete confidential information; change passwords and other authentication information; and possibly gain access to other systems within the network. This is one of the most commonly exploited categories of vulnerability, but can largely be avoided through good coding practices.", + "text": "" + }, + "properties": { + "tags": [ + "javascript", + "NoSqli", + "Security", + "SourceServer", + "SourceHttpBody", + "Taint" + ], + "categories": ["Security"], + "exampleCommitFixes": [ + { + "commitURL": "https://github.com/afuh/pinstagram/commit/776a6b63f84b3bc9d38963933ff511b319b73ac5?diff=split#diff-fb901db253d2190ed5dec3508eb32e99524e0b4dcacdaea322a50f2619ae2d99L-1", + "lines": [ + { + "line": "const user = await User.findOne({ slug: req.params.user }).populate('likes')\n", + "lineNumber": 47, + "lineChange": "removed" + }, + { + "line": "const user = await User.findOne({ _id: req.user._id }).populate('likes')\n", + "lineNumber": 47, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/mercmobily/hotplate/commit/c9dfbe8bf6bfd03838946d0898978543589a5ea2?diff=split#diff-bdb0afd700d4dfe1801bcfe39008d413182be643063835d326641fcce15b969aL-1", + "lines": [ + { + "line": " Workspace.findOne({ _id: req.params.workspaceId }, function( err, doc ){\n", + "lineNumber": 270, + "lineChange": "removed" + }, + { + "line": " workspaces.findOne({ _id: ObjectId(req.params.workspaceId) }, function( err, doc ){\n", + "lineNumber": 264, + "lineChange": "added" + }, + { + "line": " resUtils.checkFindOneResponse( err, doc, next, function(){\n", + "lineNumber": 271, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 272, + "lineChange": "none" + }, + { + "line": " perms.checkPermissions( req, next, 'workspaceConfig/get', req.body, doc, function(){\n", + "lineNumber": 273, + "lineChange": "none" + }, + { + "line": " sendResponse( res, doc.settings );\n", + "lineNumber": 274, + "lineChange": "none" + }, + { + "line": " });\n", + "lineNumber": 275, + "lineChange": "none" + }, + { + "line": " });\n", + "lineNumber": 276, + "lineChange": "none" + }, + { + "line": "});\n", + "lineNumber": 277, + "lineChange": "none" + } + ] + }, + { + "commitURL": "https://github.com/JasonEtco/flintcms/commit/4ae34238ce39fde00dfa15082397541758c07af1?diff=split#diff-9abe922e7535c6f75fba7150a7a803a93be7ae235564b86f799db9f37e4c1674L-1", + "lines": [ + { + "line": "const token = req.query.t\n", + "lineNumber": 103, + "lineChange": "removed" + }, + { + "line": "const token = req.query.t.toString()\n", + "lineNumber": 103, + "lineChange": "added" + }, + { + "line": "const user = await User.findOne({ token })\n", + "lineNumber": 104, + "lineChange": "none" + } + ] + } + ], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 30, + "cwe": ["CWE-943"] + } + }, + { + "id": "javascript/HardcodedNonCryptoSecret", + "name": "HardcodedNonCryptoSecret", + "shortDescription": { + "text": "Hardcoded Secret" + }, + "defaultConfiguration": { + "level": "error" + }, + "help": { + "markdown": "## Details\n\nWhen constants are hardcoded into applications, this information could easily be reverse-engineered and become known to attackers. For example, if a breached authentication token is hardcoded in multiple places in the application, it may lead to components of the application remaining vulnerable if not all instances are changed.\nAnother negative effect of hard-coding constants is potential unpredictability in the application's performance if the development team fails to update every single instance of the hardcoded constant throughout the code. For these reasons, hard-coding security-relevant constants is considered bad coding practice and should be remedied if present and avoided in future.\n\n## Best practices for prevention\n- Never hard code security-related constants; use symbolic names or configuration lookup files.\n- As hard coding is often done by coders working alone on a small scale, examine all legacy code components and test carefully when scaling.\n- Adopt a \"future-proof code\" mindset: While use of constants may save a little time now and make development simpler in the short term, it could cost time and money adapting to scale or other unforeseen circumstances (such as new hardware) in the future.", + "text": "" + }, + "properties": { + "tags": ["javascript", "HardcodedNonCryptoSecret", "Security"], + "categories": ["Security"], + "exampleCommitFixes": [ + { + "commitURL": "https://github.com/markstock7/FileManager/commit/50572778825dea6b6fdb34c9ae950d9915743e4c?diff=split#diff-408990876524f4737b49693cedc52fd267e31f665d0a7f71792dcb986d6a8268L-1", + "lines": [ + { + "line": "accessKeyId: 'abcdef',\n", + "lineNumber": 1, + "lineChange": "removed" + }, + { + "line": "secretAccessKey: 'abcdef',\n", + "lineNumber": 2, + "lineChange": "removed" + }, + { + "line": "accessKeyId: '',\n", + "lineNumber": 1, + "lineChange": "added" + }, + { + "line": "secretAccessKey: '',\n", + "lineNumber": 2, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/rodrigotamura/go-stack-2019/commit/26e020dfc2272fe76c82c28d86f492c3c84a94c5?diff=split#diff-92f76c0bccc1f970244da3b50449f200d4787cf60a87be14ff4f250d0ba1a590L-1", + "lines": [ + { + "line": "secret: 'abcdef',\n", + "lineNumber": 1, + "lineChange": "removed" + }, + { + "line": "secret: process.env.APP_SECRET,\n", + "lineNumber": 1, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/appcypher/events-manager-io/commit/656fdf6bfb902894db36b4b3ea98441ee607b75e?diff=split#diff-0cd5bb6f9779938a122d3bfef4a22f6fc66e59742c3a377dde667d8a6c5f5e16L-1", + "lines": [ + { + "line": "password: bcrypt.hashSync('admin', 10),\n", + "lineNumber": 6, + "lineChange": "removed" + }, + { + "line": "password: bcrypt.hashSync(process.env.ADMIN_SEED_PASSWORD, 10),\n", + "lineNumber": 10, + "lineChange": "added" + } + ] + } + ], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 68, + "cwe": ["CWE-547"] + } + }, + { + "id": "javascript/DisablePoweredBy", + "name": "DisablePoweredBy", + "shortDescription": { + "text": "Information Exposure" + }, + "defaultConfiguration": { + "level": "warning" + }, + "help": { + "markdown": "## Details\n\nSensitive data includes: personally identifiable information (PII) of employees, customers, users, or other third parties; financial information; code; intellectual property; or protected network information such as passwords. Exposure of sensitive information to an unauthorized actor occurs when any party who does not require this information for business purposes can remove this information from the secure network.\nConsequences of exposure can include holding it for ransom payment, identity theft, or access to other internal network resources-along with financial loss due to regulatory fines, court settlements, or cost to restore compromised systems. As most attackers aim to extract sensitive information, this CWE only describes exploits that take advantage of vulnerabilities related to how data is handled: the management, storage, transfer, or removal of sensitive information.\n\n## Best practices for prevention\n- Encrypt data at all times, whether in transit or at rest.\n- When transporting data, always use a secure protocol such as TLS.\n- Before collecting PII or financial information, consider whether there is a true business need for this information; similarly, before storing the data, ensure that there is an ongoing business need.\n- Classify all incoming data according to privacy and security guidelines to improve awareness of sensitive data.\n- Ensure that caching is disabled for all transactions involving sensitive information.\n- Store passwords with secure, salted hashing functions.\n- Apply a network-wide least-privilege policy so sensitive data is provided only to users with business need to know.", + "text": "" + }, + "properties": { + "tags": ["javascript", "DisablePoweredBy", "Security"], + "categories": ["Security"], + "exampleCommitFixes": [ + { + "commitURL": "https://github.com/lucasweng/yelp-camp/commit/f4e907734aea3ec98000d61f5d49c729a95cb77c?diff=split#diff-e07d531ac040ce3f40e0ce632ac2a059d7cd60f20e61f78268ac3be015b3b28fL-1", + "lines": [ + { + "line": " app = express(),\n", + "lineNumber": 1, + "lineChange": "none" + }, + { + "line": " bodyParser = require(\"body-parser\"),\n", + "lineNumber": 2, + "lineChange": "none" + }, + { + "line": " mongoose = require(\"mongoose\"),\n", + "lineNumber": 3, + "lineChange": "none" + }, + { + "line": " helmet = require(\"helmet\"),\n", + "lineNumber": 4, + "lineChange": "added" + }, + { + "line": " flash = require(\"connect-flash\"),\n", + "lineNumber": 5, + "lineChange": "none" + }, + { + "line": " session = require(\"express-session\"),\n", + "lineNumber": 6, + "lineChange": "none" + }, + { + "line": " moment = require(\"moment\"),\n", + "lineNumber": 7, + "lineChange": "none" + }, + { + "line": " passport = require(\"passport\"),\n", + "lineNumber": 8, + "lineChange": "none" + }, + { + "line": " LocalStrategy = require(\"passport-local\"),\n", + "lineNumber": 9, + "lineChange": "none" + }, + { + "line": " methodOverride = require(\"method-override\"),\n", + "lineNumber": 10, + "lineChange": "none" + }, + { + "line": " User = require(\"./models/user\");\n", + "lineNumber": 11, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 12, + "lineChange": "none" + }, + { + "line": "// requiring routes \n", + "lineNumber": 13, + "lineChange": "none" + }, + { + "line": "const indexRoute = require(\"./routes/index\"),\n", + "lineNumber": 14, + "lineChange": "none" + }, + { + "line": " campgroundRoute = require(\"./routes/campgrounds\"),\n", + "lineNumber": 15, + "lineChange": "none" + }, + { + "line": " commentRoute = require(\"./routes/comments\"),\n", + "lineNumber": 16, + "lineChange": "none" + }, + { + "line": " userRoute = require(\"./routes/user\"),\n", + "lineNumber": 17, + "lineChange": "none" + }, + { + "line": " passwordRoute = require(\"./routes/password\");\n", + "lineNumber": 18, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 19, + "lineChange": "none" + }, + { + "line": "// connect to the DB\n", + "lineNumber": 20, + "lineChange": "none" + }, + { + "line": "let url = process.env.DATABASEURL || \"mongodb://localhost/yelp_camp_v13\"; // fallback in case global var not working\n", + "lineNumber": 21, + "lineChange": "none" + }, + { + "line": "mongoose.connect(url, {useMongoClient: true});\n", + "lineNumber": 22, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 23, + "lineChange": "none" + }, + { + "line": "app.set(\"view engine\", \"ejs\");\n", + "lineNumber": 24, + "lineChange": "none" + }, + { + "line": "app.use(helmet());\n", + "lineNumber": 25, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/infor-design/enterprise/commit/20888f176d6bccc41b009a54b2d47a2b29845db3?diff=split#diff-322f0482bd28fc40f84fcb0aaf208fef7fb63082d462cf02d11f46e59c531c24L-1", + "lines": [ + { + "line": "const app = express();\n", + "lineNumber": 9, + "lineChange": "none" + }, + { + "line": "const BASE_PATH = process.env.BASEPATH || '/';\n", + "lineNumber": 10, + "lineChange": "none" + }, + { + "line": "const packageJSON = getJSONFile('../../../package.json');\n", + "lineNumber": 11, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 12, + "lineChange": "none" + }, + { + "line": "app.set('view engine', 'html');\n", + "lineNumber": 13, + "lineChange": "none" + }, + { + "line": "app.set('views', path.resolve(__dirname, 'views'));\n", + "lineNumber": 14, + "lineChange": "none" + }, + { + "line": "app.set('basepath', BASE_PATH);\n", + "lineNumber": 15, + "lineChange": "none" + }, + { + "line": "app.disable('x-powered-by');\n", + "lineNumber": 16, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/galtenberg/evernote-random/commit/32109271055df8a60bf4dafe289b717dbb950305?diff=split#diff-bcb729747c92e72c12e4590f736a334041a572c429756da8af60b6ab89c6be79L-1", + "lines": [ + { + "line": "const csp = require('helmet-csp')\n", + "lineNumber": 5, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 6, + "lineChange": "none" + }, + { + "line": "const app = express()\n", + "lineNumber": 7, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 8, + "lineChange": "none" + }, + { + "line": "app.use(morgan(':remote-addr - :remote-user [:date[clf]] \":method :url HTTP/:http-version\" :status :res[content-length] :response-time ms'));\n", + "lineNumber": 9, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 10, + "lineChange": "none" + }, + { + "line": "// parse application/x-www-form-urlencoded\n", + "lineNumber": 11, + "lineChange": "none" + }, + { + "line": "app.use(bodyParser.urlencoded({ extended: false }))\n", + "lineNumber": 12, + "lineChange": "none" + }, + { + "line": "// json parser\n", + "lineNumber": 13, + "lineChange": "none" + }, + { + "line": "app.use(bodyParser.json())\n", + "lineNumber": 14, + "lineChange": "none" + }, + { + "line": "// Serve static assets\n", + "lineNumber": 15, + "lineChange": "none" + }, + { + "line": "app.use(express.static(path.resolve(__dirname, '..', 'build')))\n", + "lineNumber": 15, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 17, + "lineChange": "none" + }, + { + "line": "// Re-enable on glitch.com\n", + "lineNumber": 18, + "lineChange": "none" + }, + { + "line": "// Always return the main index.html, so react-router render the route in the client\n", + "lineNumber": 19, + "lineChange": "none" + }, + { + "line": "//app.get('*', (req, res) =\u003e {\n", + "lineNumber": 19, + "lineChange": "none" + }, + { + "line": " //res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));\n", + "lineNumber": 21, + "lineChange": "none" + }, + { + "line": "//})\n", + "lineNumber": 22, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 23, + "lineChange": "none" + }, + { + "line": "app.use(cookieSession({\n", + "lineNumber": 24, + "lineChange": "none" + }, + { + "line": " name: 'evernoteSolitaire',\n", + "lineNumber": 25, + "lineChange": "none" + }, + { + "line": " secret: 'evernote-sandbox-secret',\n", + "lineNumber": 26, + "lineChange": "none" + }, + { + "line": " maxAge: 30 * 24 * 60 * 60 * 1000 // 1 month\n", + "lineNumber": 27, + "lineChange": "none" + }, + { + "line": "}))\n", + "lineNumber": 28, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 29, + "lineChange": "none" + }, + { + "line": "//require('./api/experiment')(app)\n", + "lineNumber": 29, + "lineChange": "none" + }, + { + "line": "require('./api/auth')(app)\n", + "lineNumber": 30, + "lineChange": "none" + }, + { + "line": "require('./api/notes')(app)\n", + "lineNumber": 31, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 32, + "lineChange": "none" + }, + { + "line": "const PORT = process.env.PORT || 8000\n", + "lineNumber": 33, + "lineChange": "removed" + }, + { + "line": "app.use(bodyParser.json({\n", + "lineNumber": 33, + "lineChange": "added" + }, + { + "line": " type: ['json', 'application/csp-report']\n", + "lineNumber": 34, + "lineChange": "added" + }, + { + "line": "}))\n", + "lineNumber": 35, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 36, + "lineChange": "added" + }, + { + "line": "app.post('/report-violation', function (req, res) {\n", + "lineNumber": 37, + "lineChange": "added" + }, + { + "line": " if (req.body) {\n", + "lineNumber": 38, + "lineChange": "added" + }, + { + "line": " console.log('CSP Violation: ', req.body)\n", + "lineNumber": 39, + "lineChange": "added" + }, + { + "line": " } else {\n", + "lineNumber": 40, + "lineChange": "added" + }, + { + "line": " console.log('CSP Violation: No data received!')\n", + "lineNumber": 41, + "lineChange": "added" + }, + { + "line": " }\n", + "lineNumber": 42, + "lineChange": "added" + }, + { + "line": " res.status(204).end()\n", + "lineNumber": 43, + "lineChange": "added" + }, + { + "line": "})\n", + "lineNumber": 44, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 45, + "lineChange": "added" + }, + { + "line": "const PORT = 8000 //process.env.PORT || 8000\n", + "lineNumber": 46, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 47, + "lineChange": "added" + }, + { + "line": "app.use(csp({\n", + "lineNumber": 48, + "lineChange": "added" + }, + { + "line": " directives: {\n", + "lineNumber": 49, + "lineChange": "added" + }, + { + "line": " defaultSrc: [\"'self'\"],\n", + "lineNumber": 50, + "lineChange": "added" + }, + { + "line": " scriptSrc: [\"'unsafe-inline'\"],\n", + "lineNumber": 51, + "lineChange": "added" + }, + { + "line": " styleSrc: [\"'unsafe-inline'\"],\n", + "lineNumber": 52, + "lineChange": "added" + }, + { + "line": " reportUri: '/report-violation',\n", + "lineNumber": 53, + "lineChange": "added" + }, + { + "line": " upgradeInsecureRequests: true\n", + "lineNumber": 54, + "lineChange": "added" + }, + { + "line": " },\n", + "lineNumber": 55, + "lineChange": "added" + }, + { + "line": " reportOnly: false,\n", + "lineNumber": 56, + "lineChange": "added" + }, + { + "line": " loose: true,\n", + "lineNumber": 57, + "lineChange": "added" + }, + { + "line": " setAllHeaders: true,\n", + "lineNumber": 58, + "lineChange": "added" + }, + { + "line": " browserSniff: false\n", + "lineNumber": 59, + "lineChange": "added" + }, + { + "line": "}))\n", + "lineNumber": 60, + "lineChange": "added" + } + ] + } + ], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 416, + "cwe": ["CWE-200"] + } + }, + { + "id": "javascript/HttpToHttps", + "name": "HttpToHttps", + "shortDescription": { + "text": "Cleartext Transmission of Sensitive Information" + }, + "defaultConfiguration": { + "level": "warning" + }, + "help": { + "markdown": "\n## Details\nThis weakness occurs when software transmits sensitive information, such as passwords or credit card numbers, in unencrypted form. This information may then be intercepted by threat actors using sniffer tools or interception techniques such as man-in-the-middle (MITM) attacks (often involving social engineering). Attackers can then use information gleaned to perform a variety of actions, depending on the information type. Possible actions include gaining unauthorized access, impersonating a user, moving laterally within the organization's network, or retrieving and potentially modifying files. This weakness is almost completely avoidable through intelligent architecture and design.\n\n## Best practices for prevention\n* Build web applications around a security mindset and the awareness that sniffers may be present at any time.\n* Ensure that all sensitive data transmission uses reliable encryption.\n* Implement security measures so that sensitive results are never returned in plain text.\n* Implement multiple-factor authentication methods to validate remote instances.\n* Use SSL not only at logon but throughout communications.", + "text": "" + }, + "properties": { + "tags": ["javascript", "HttpToHttps", "Security"], + "categories": ["Security"], + "exampleCommitFixes": [ + { + "commitURL": "https://github.com/eserozvataf/apibone/commit/bbac9343971a20f4fee124b6f0a2f6a80895fb35?diff=split#diff-8b733ca241b0609b1fc0f2e60d14f911b3a82997a939e7eb01fe6c25b759c234L-1", + "lines": [ + { + "line": "const http = require('http'),\n", + "lineNumber": 0, + "lineChange": "removed" + }, + { + "line": "const https = require('https'),\n", + "lineNumber": 0, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/RetireJS/retire.js/commit/82d44d60c98acba0e4c3772709e76b989c4274bb?diff=split#diff-89d400752fb89d946a43778e9f0b3dba25968dcdf8604ae08adbb3ecb236338fL-1", + "lines": [ + { + "line": "var http = require('http'),\n", + "lineNumber": 1, + "lineChange": "removed" + }, + { + "line": "var http = require('https'),\n", + "lineNumber": 1, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/Rich-Harris/packd/commit/c14d17da80ed075ee007de3121422fb2c5b77e4d?diff=split#diff-1821d11fbffbab2187701c42616688d46bf66d7b2cf6eaf363548dd66caa6ebaL-1", + "lines": [ + { + "line": "const http = require( 'http' );\n", + "lineNumber": 0, + "lineChange": "removed" + }, + { + "line": "const https = require( 'https' );\n", + "lineNumber": 0, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 1, + "lineChange": "none" + }, + { + "line": "module.exports = function get ( url ) {\n", + "lineNumber": 2, + "lineChange": "none" + }, + { + "line": "\treturn new Promise( ( fulfil, reject ) =\u003e {\n", + "lineNumber": 3, + "lineChange": "none" + }, + { + "line": "\t\thttp.get( url, response =\u003e {\n", + "lineNumber": 4, + "lineChange": "removed" + }, + { + "line": "\t\thttps.get( url, response =\u003e {\n", + "lineNumber": 4, + "lineChange": "added" + } + ] + } + ], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 122, + "cwe": ["CWE-319"] + } + }, + { + "id": "javascript/UseCsurfForExpress", + "name": "UseCsurfForExpress", + "shortDescription": { + "text": "Cross-Site Request Forgery (CSRF)" + }, + "defaultConfiguration": { + "level": "warning" + }, + "help": { + "markdown": "\n## Details\nCross-site request forgery is an attack in which a malicious third party takes advantage of a user's authenticated credentials (such as a browser cookie) to impersonate that trusted user and perform unauthorized actions. The web application server cannot tell the difference between legitimate and malicious requests. This type of attack generally begins by tricking the user with a social engineering attack, such as a link or popup that the user inadvertently clicks, causing an unauthorized request to be sent to the web server. Consequences vary: At a standard user level, attackers can change passwords, transfer funds, make purchases, or connect with contacts; from an administrator account, attackers can then make changes to or even take down the app itself.\n\n## Best practices for prevention\n* Use development frameworks that defend against CSRF, using a nonce, hash, or some other security device to the URL and/or to forms.\n* Implement secure, unique, hidden tokens that are checked by the server each time to validate state-change requests.\n* Never assume that authentication tokens and session identifiers mean a request is legitimate.\n* Understand and implement other safe-cookie techniques, such as double submit cookies.\n* Terminate user sessions when not in use, including automatic timeout.\n* Ensure rigorous coding practices and defenses against other commonly exploited CWEs, since cross-site scripting (XSS), for example, can be used to bypass defenses against CSRF.\n\n## References\n* [Snyk Learn - CSRF](https://learn.snyk.io/lesson/csrf-attack/)", + "text": "" + }, + "properties": { + "tags": ["javascript", "UseCsurfForExpress", "Security"], + "categories": ["Security"], + "exampleCommitFixes": [ + { + "commitURL": "https://github.com/ruderngespra/socialnetwork/commit/06b5f8bd68460526666b4e3af546fa5150ab15b5?diff=split#diff-e727e4bdf3657fd1d798edcd6b099d6e092f8573cba266154583a746bba0f346L-1", + "lines": [ + { + "line": "const app = express();\n", + "lineNumber": 1, + "lineChange": "none" + }, + { + "line": "const compression = require(\"compression\");\n", + "lineNumber": 2, + "lineChange": "none" + }, + { + "line": "const csurf = require(\"csurf\");\n", + "lineNumber": 3, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 4, + "lineChange": "none" + }, + { + "line": "app.use(require(\"body-parser\").json());\n", + "lineNumber": 5, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 6, + "lineChange": "none" + }, + { + "line": "app.use(\n", + "lineNumber": 7, + "lineChange": "none" + }, + { + "line": " require(\"cookie-session\")({\n", + "lineNumber": 8, + "lineChange": "none" + }, + { + "line": " secret: \"I am nearly always happy.\",\n", + "lineNumber": 9, + "lineChange": "none" + }, + { + "line": " maxAge: 24 * 60 * 60 * 1000\n", + "lineNumber": 10, + "lineChange": "none" + }, + { + "line": " })\n", + "lineNumber": 11, + "lineChange": "none" + }, + { + "line": ");\n", + "lineNumber": 12, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 13, + "lineChange": "none" + }, + { + "line": "app.use(csurf());\n", + "lineNumber": 14, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 15, + "lineChange": "added" + }, + { + "line": "app.use(function(req, res, next) {\n", + "lineNumber": 16, + "lineChange": "added" + }, + { + "line": " res.cookie(\"mytoken\", req.csrfToken());\n", + "lineNumber": 17, + "lineChange": "added" + }, + { + "line": " next();\n", + "lineNumber": 18, + "lineChange": "added" + }, + { + "line": "});\n", + "lineNumber": 19, + "lineChange": "added" + }, + { + "line": "\n", + "lineNumber": 20, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/bem-site/bem-forum/commit/fe91f3733daf1b0ccf726f4f9f2cfc007c9fbad7?diff=split#diff-bcb729747c92e72c12e4590f736a334041a572c429756da8af60b6ab89c6be79L-1", + "lines": [ + { + "line": " app = express();\n", + "lineNumber": 17, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 18, + "lineChange": "none" + }, + { + "line": "if(util.isDev()) {\n", + "lineNumber": 19, + "lineChange": "none" + }, + { + "line": " app.use(require('enb/lib/server/server-middleware').createMiddleware({\n", + "lineNumber": 20, + "lineChange": "none" + }, + { + "line": " cdir: process.cwd(),\n", + "lineNumber": 21, + "lineChange": "none" + }, + { + "line": " noLog: false\n", + "lineNumber": 22, + "lineChange": "none" + }, + { + "line": " }));\n", + "lineNumber": 23, + "lineChange": "none" + }, + { + "line": "}\n", + "lineNumber": 24, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 25, + "lineChange": "none" + }, + { + "line": "app.set('port', process.env.PORT || config.port);\n", + "lineNumber": 26, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 27, + "lineChange": "none" + }, + { + "line": "app\n", + "lineNumber": 28, + "lineChange": "none" + }, + { + "line": " .use(st(process.cwd()))\n", + "lineNumber": 29, + "lineChange": "none" + }, + { + "line": " .use(favicon(process.cwd() + '/public/favicon.ico'))\n", + "lineNumber": 30, + "lineChange": "none" + }, + { + "line": " .use(cookieParser()) //also is necessary for forum\n", + "lineNumber": 31, + "lineChange": "removed" + }, + { + "line": " .use(bodyParser()) //also is necessary for forum\n", + "lineNumber": 32, + "lineChange": "removed" + }, + { + "line": " .use(session({ secret: 'forum-session', saveUninitialized: true, resave: true }))\n", + "lineNumber": 33, + "lineChange": "removed" + }, + { + "line": " .use(cookieParser())\n", + "lineNumber": 31, + "lineChange": "added" + }, + { + "line": " .use(bodyParser())\n", + "lineNumber": 32, + "lineChange": "added" + }, + { + "line": " .use(session({ secret: 'beminfoforum', saveUninitialized: false, resave: false }))\n", + "lineNumber": 33, + "lineChange": "added" + }, + { + "line": " .use(csrf())\n", + "lineNumber": 34, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/Shyam-Chen/Express-Starter/commit/9a98ac310f7a49dd97da4a4b7a53bfc74b0cc35e?diff=split#diff-c72a907ac323cd2f334ed0e2bd07d15ab62581c4753660c8a0d1c681b30be4b6L-1", + "lines": [ + { + "line": "import csurf from 'csurf';\n", + "lineNumber": 10, + "lineChange": "added" + }, + { + "line": "import connectRedis from 'connect-redis';\n", + "lineNumber": 11, + "lineChange": "none" + }, + { + "line": "import rendertron from 'rendertron-middleware';\n", + "lineNumber": 12, + "lineChange": "none" + }, + { + "line": "import history from 'express-history-api-fallback';\n", + "lineNumber": 13, + "lineChange": "none" + }, + { + "line": "import Raven from 'raven';\n", + "lineNumber": 14, + "lineChange": "none" + }, + { + "line": "import chalk from 'chalk';\n", + "lineNumber": 15, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 16, + "lineChange": "none" + }, + { + "line": "import routes from '~/core/rest';\n", + "lineNumber": 17, + "lineChange": "none" + }, + { + "line": "import apolloServer from '~/core/graphql';\n", + "lineNumber": 18, + "lineChange": "none" + }, + { + "line": "import mongoose from '~/core/mongoose';\n", + "lineNumber": 19, + "lineChange": "none" + }, + { + "line": "import sequelize from '~/core/sequelize';\n", + "lineNumber": 20, + "lineChange": "none" + }, + { + "line": "import passport from '~/core/passport';\n", + "lineNumber": 21, + "lineChange": "none" + }, + { + "line": "import redis from '~/core/redis';\n", + "lineNumber": 22, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 23, + "lineChange": "none" + }, + { + "line": "import {\n", + "lineNumber": 24, + "lineChange": "none" + }, + { + "line": " NODE_ENV, PORT, HOST, SECRET,\n", + "lineNumber": 25, + "lineChange": "none" + }, + { + "line": " SENTRY_DSN, STATIC_FILES, RENDERTRON_URL,\n", + "lineNumber": 26, + "lineChange": "none" + }, + { + "line": "} from './env';\n", + "lineNumber": 27, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 28, + "lineChange": "none" + }, + { + "line": "const app = express();\n", + "lineNumber": 29, + "lineChange": "none" + }, + { + "line": "const server = http.Server(app);\n", + "lineNumber": 30, + "lineChange": "none" + }, + { + "line": "const io = socket(server);\n", + "lineNumber": 31, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 32, + "lineChange": "none" + }, + { + "line": "app.set('socket', io);\n", + "lineNumber": 33, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 34, + "lineChange": "none" + }, + { + "line": "if (NODE_ENV === 'production') Raven.config(SENTRY_DSN).install();\n", + "lineNumber": 35, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 36, + "lineChange": "none" + }, + { + "line": "/**\n", + "lineNumber": 37, + "lineChange": "none" + }, + { + "line": " * @name middleware-functions\n", + "lineNumber": 38, + "lineChange": "none" + }, + { + "line": " */\n", + "lineNumber": 39, + "lineChange": "none" + }, + { + "line": "app.use(helmet());\n", + "lineNumber": 40, + "lineChange": "none" + }, + { + "line": "app.use(cors());\n", + "lineNumber": 41, + "lineChange": "none" + }, + { + "line": "// app.use(csurf());\n", + "lineNumber": 42, + "lineChange": "none" + }, + { + "line": "// app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));\n", + "lineNumber": 43, + "lineChange": "none" + }, + { + "line": "app.use(compression());\n", + "lineNumber": 44, + "lineChange": "none" + }, + { + "line": "app.use(morgan('tiny'));\n", + "lineNumber": 45, + "lineChange": "none" + }, + { + "line": "app.use(express.json());\n", + "lineNumber": 46, + "lineChange": "none" + }, + { + "line": "app.use(express.urlencoded({ extended: false }));\n", + "lineNumber": 47, + "lineChange": "none" + }, + { + "line": "app.use(session({\n", + "lineNumber": 48, + "lineChange": "none" + }, + { + "line": " store: new (connectRedis(session))({ client: redis }),\n", + "lineNumber": 49, + "lineChange": "none" + }, + { + "line": " name: 'sid',\n", + "lineNumber": 50, + "lineChange": "none" + }, + { + "line": " resave: true,\n", + "lineNumber": 51, + "lineChange": "none" + }, + { + "line": " saveUninitialized: true,\n", + "lineNumber": 52, + "lineChange": "none" + }, + { + "line": " secret: SECRET,\n", + "lineNumber": 53, + "lineChange": "none" + }, + { + "line": "}));\n", + "lineNumber": 54, + "lineChange": "none" + }, + { + "line": "app.use(passport.initialize());\n", + "lineNumber": 55, + "lineChange": "none" + }, + { + "line": "app.use(passport.session());\n", + "lineNumber": 56, + "lineChange": "none" + }, + { + "line": "app.use(csurf());\n", + "lineNumber": 56, + "lineChange": "added" + } + ] + } + ], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 66, + "cwe": ["CWE-352"] + } + }, + { + "id": "javascript/NoHardcodedPasswords", + "name": "NoHardcodedPasswords", + "shortDescription": { + "text": "Use of Hardcoded Credentials" + }, + "defaultConfiguration": { + "level": "warning" + }, + "help": { + "markdown": "\n## Details\n\nDevelopers may use hardcoded credentials for convenience when coding in order to simplify their workflow. While they are responsible for removing these before production, occasionally this task may fall through the cracks. This also becomes a maintenance challenge when credentials are re-used across multiple applications.\n\nOnce attackers gain access, they may take advantage of privilege level to remove or alter data, take down a site or app, or hold any of the above for ransom. The risk across multiple similar projects is even greater. If code containing the credentials is reused across multiple projects, they will all be compromised.\n\n## Best practices for prevention\n* Plan software architecture such that keys and passwords are always stored outside the code, wherever possible.\n* Plan encryption into software architecture for all credential information and ensure proper handling of keys, credentials, and passwords.\n* Prompt for a secure password on first login rather than hard-code a default password.\n* If a hardcoded password or credential must be used, limit its use, for example, to system console users rather than via the network.\n* Use strong hashes for inbound password authentication, ideally with randomly assigned salts to increase the difficulty level in case of brute-force attack.", + "text": "" + }, + "properties": { + "tags": ["javascript", "NoHardcodedPasswords", "Security"], + "categories": ["Security"], + "exampleCommitFixes": [ + { + "commitURL": "https://github.com/Gitualize/Gitualize/commit/f6de5689d637dc41abd4b43eea40371fd1088d33?diff=split#diff-273ae97b30b3f18c1d3fc9bf418b55be30c6e4a19f3f51953362cfa762980c63L-1", + "lines": [ + { + "line": "user: 'docker',\n", + "lineNumber": 2, + "lineChange": "removed" + }, + { + "line": "password: 'docker',\n", + "lineNumber": 3, + "lineChange": "removed" + }, + { + "line": "database: 'docker',\n", + "lineNumber": 4, + "lineChange": "removed" + }, + { + "line": "user: process.env.DATABASE_USER,\n", + "lineNumber": 2, + "lineChange": "added" + }, + { + "line": "password: process.env.DATABASE_PASSWORD,\n", + "lineNumber": 3, + "lineChange": "added" + }, + { + "line": "database: process.env.DATABASE_NAME,\n", + "lineNumber": 4, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/UsabilityDynamics/node-rabbit-client/commit/bf652950ac5eb1cd85ebe349b29ad045df51dd07?diff=split#diff-506a1dcb4e0d34ef96430d0fa0790cc3e84cbf193ea91b3e49e5e52c86dad0f4L-1", + "lines": [ + { + "line": "login : 'udx',\n", + "lineNumber": 5, + "lineChange": "removed" + }, + { + "line": "password : 'ISM0Rules'\n", + "lineNumber": 6, + "lineChange": "removed" + }, + { + "line": "login : process.env.RABBIT_LOGIN,\n", + "lineNumber": 5, + "lineChange": "added" + }, + { + "line": "password : process.env.RABBIT_PASSWORD\n", + "lineNumber": 6, + "lineChange": "added" + } + ] + }, + { + "commitURL": "https://github.com/perborgen/data_hub/commit/8de6d9c7efdc6d0a773808c872c83f3374643a8e?diff=split#diff-58417e0f781b6656949d37258c8b9052ed266e2eb7a5163cad7b0863e6b2916aL-1", + "lines": [ + { + "line": "var config = require('./config');\n", + "lineNumber": 2, + "lineChange": "none" + }, + { + "line": "var handler = require('./api/handler');\n", + "lineNumber": 3, + "lineChange": "none" + }, + { + "line": "var inert = require('inert');\n", + "lineNumber": 4, + "lineChange": "none" + }, + { + "line": "var bell = require('bell');\n", + "lineNumber": 5, + "lineChange": "none" + }, + { + "line": "var hapiAC = require('hapi-auth-cookie');\n", + "lineNumber": 6, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 7, + "lineChange": "none" + }, + { + "line": "server.connection({\n", + "lineNumber": 8, + "lineChange": "none" + }, + { + "line": " port: process.env.PORT || 8080,\n", + "lineNumber": 9, + "lineChange": "none" + }, + { + "line": " host: \"0.0.0.0\" || \"localhost\"\n", + "lineNumber": 10, + "lineChange": "none" + }, + { + "line": "});\n", + "lineNumber": 11, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 12, + "lineChange": "none" + }, + { + "line": "server.register([inert, bell, hapiAC], function(err){\n", + "lineNumber": 13, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 14, + "lineChange": "none" + }, + { + "line": " if (err) {\n", + "lineNumber": 15, + "lineChange": "none" + }, + { + "line": " throw err;\n", + "lineNumber": 16, + "lineChange": "none" + }, + { + "line": " }\n", + "lineNumber": 17, + "lineChange": "none" + }, + { + "line": "\n", + "lineNumber": 18, + "lineChange": "none" + }, + { + "line": " var authCookieOptions = {\n", + "lineNumber": 19, + "lineChange": "none" + }, + { + "line": " password: 'cookie-encryption-password', //Password used for encryption\n", + "lineNumber": 20, + "lineChange": "removed" + }, + { + "line": " cookie: 'sitepoint-auth', // Name of cookie to set\n", + "lineNumber": 21, + "lineChange": "removed" + }, + { + "line": " password: config.password || process.env.PASSWORD, //Password used for encryption\n", + "lineNumber": 20, + "lineChange": "added" + }, + { + "line": " cookie: 'auth', // Name of cookie to set\n", + "lineNumber": 21, + "lineChange": "added" + } + ] + } + ], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 44, + "cwe": ["CWE-798", "CWE-259"] + } + } + ] + } + }, + "results": [ + { + "ruleId": "javascript/NoRateLimitingForExpensiveWebOperation", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "This endpoint handler performs a system command execution and does not use a rate-limiting mechanism. It may enable the attackers to perform Denial-of-service attacks. Consider using a rate-limiting middleware such as express-limit.", + "markdown": "This {0} performs {1} and does not use a rate-limiting mechanism. It may enable the attackers to perform Denial-of-service attacks. Consider using a rate-limiting middleware such as express-limit.", + "arguments": [ + "[endpoint handler](0)", + "[a system command execution](1)" + ] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 77, + "endLine": 113, + "startColumn": 18, + "endColumn": 2 + } + } + } + ], + "fingerprints": { + "0": "f927008c43b00df60dbeccb9e5565bb0529ea1454f7e3e665d29c61801357953", + "1": "a3c051e6.9c6e2949.98501263.c559ebce.b5c66366.5fce695c.83265159.89d75565.a3c051e6.4773f344.c2905f73.c559ebce.b6be8b13.5fce695c.83265159.89d75565", + "identity": "5fe97046-d8ce-45c3-82e5-8756e8ffe20c" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 77, + "endLine": 113, + "startColumn": 18, + "endColumn": 2 + } + } + } + }, + { + "location": { + "id": 1, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 86, + "endLine": 86, + "startColumn": 10, + "endColumn": 27 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 578, + "priorityScoreFactors": [ + { + "label": true, + "type": "multipleOccurrence" + }, + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "javascript/NoRateLimitingForExpensiveWebOperation", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "This endpoint handler performs a file system operation and does not use a rate-limiting mechanism. It may enable the attackers to perform Denial-of-service attacks. Consider using a rate-limiting middleware such as express-limit.", + "markdown": "This {0} performs {1} and does not use a rate-limiting mechanism. It may enable the attackers to perform Denial-of-service attacks. Consider using a rate-limiting middleware such as express-limit.", + "arguments": [ + "[endpoint handler](0)", + "[a file system operation](1)" + ] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 166, + "endLine": 220, + "startColumn": 18, + "endColumn": 2 + } + } + } + ], + "fingerprints": { + "0": "c2357a8e5cf9d2246841d185e94a82260932a6b66fb086b92a0fc28744a2ea65", + "1": "ae77ea27.9c6e2949.98501263.c559ebce.fd1fa73f.5fce695c.83265159.89d75565.c3f8dfad.4773f344.1ec824b2.c559ebce.546471fb.5fce695c.83265159.2f05c567", + "identity": "6036809b-b137-44f1-b44e-98cf08fd8e37" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 166, + "endLine": 220, + "startColumn": 18, + "endColumn": 2 + } + } + } + }, + { + "location": { + "id": 1, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 184, + "endLine": 184, + "startColumn": 5, + "endColumn": 16 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 578, + "priorityScoreFactors": [ + { + "label": true, + "type": "multipleOccurrence" + }, + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "javascript/NoRateLimitingForExpensiveWebOperation", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "This endpoint handler performs a file system operation and does not use a rate-limiting mechanism. It may enable the attackers to perform Denial-of-service attacks. Consider using a rate-limiting middleware such as express-limit.", + "markdown": "This {0} performs {1} and does not use a rate-limiting mechanism. It may enable the attackers to perform Denial-of-service attacks. Consider using a rate-limiting middleware such as express-limit.", + "arguments": [ + "[endpoint handler](0)", + "[a file system operation](1)" + ] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 222, + "endLine": 230, + "startColumn": 21, + "endColumn": 2 + } + } + } + ], + "fingerprints": { + "0": "48a814ab1cfc6be77ad23666764c1d71bddffb00ea0d83a9a17ab3d72e797bb2", + "1": "ae77ea27.4773f344.607187b5.1c17f46e.93e94ad5.5fce695c.83265159.89d75565.ae77ea27.4773f344.607187b5.1c17f46e.93e94ad5.5fce695c.83265159.89d75565", + "identity": "84bef90d-511b-4645-b0e4-fbfcdc3721fd" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 222, + "endLine": 230, + "startColumn": 21, + "endColumn": 2 + } + } + } + }, + { + "location": { + "id": 1, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 224, + "endLine": 224, + "startColumn": 16, + "endColumn": 22 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 578, + "priorityScoreFactors": [ + { + "label": true, + "type": "multipleOccurrence" + }, + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "javascript/NoSqli", + "ruleIndex": 1, + "level": "error", + "message": { + "text": "Unsanitized input from the HTTP request body flows into find, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.", + "markdown": "Unsanitized input from {0} {1} into {2}, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.", + "arguments": [ + "[the HTTP request body](0)", + "[flows](1),(2),(3),(4)", + "[find](5)" + ] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 39, + "endLine": 39, + "startColumn": 8, + "endColumn": 12 + } + } + } + ], + "fingerprints": { + "0": "5dacd021007d5479cb1b35404420a56a7fc14480d99c3f62ac16a87ad2bfe1ed", + "1": "12567ef6.4773f344.7fde84c3.750eb3ec.cea4e9be.8020cfdf.cd61fc56.3cd69235.f759b1f9.4773f344.7fde84c3.08906714.79a7d027.5fce695c.c0a0d45c.1ce8e212", + "identity": "0e275117-61b7-4344-b310-1b6e61fb5af5" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 39, + "endLine": 39, + "startColumn": 29, + "endColumn": 33 + } + } + } + }, + { + "location": { + "id": 1, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 39, + "endLine": 39, + "startColumn": 29, + "endColumn": 33 + } + } + } + }, + { + "location": { + "id": 2, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 39, + "endLine": 39, + "startColumn": 25, + "endColumn": 33 + } + } + } + }, + { + "location": { + "id": 3, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 39, + "endLine": 39, + "startColumn": 15, + "endColumn": 23 + } + } + } + }, + { + "location": { + "id": 4, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 39, + "endLine": 39, + "startColumn": 13, + "endColumn": 73 + } + } + } + }, + { + "location": { + "id": 5, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 39, + "endLine": 39, + "startColumn": 8, + "endColumn": 12 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 828, + "priorityScoreFactors": [ + { + "label": true, + "type": "multipleOccurrence" + }, + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "javascript/NoSqli", + "ruleIndex": 1, + "level": "error", + "message": { + "text": "Unsanitized input from an HTTP parameter flows into findById, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.", + "markdown": "Unsanitized input from {0} {1} into {2}, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.", + "arguments": [ + "[an HTTP parameter](0)", + "[flows](1),(2),(3)", + "[findById](4)" + ] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 116, + "endLine": 116, + "startColumn": 8, + "endColumn": 16 + } + } + } + ], + "fingerprints": { + "0": "554c9e4d45c7e592d275a3ed9e055135b84585bdbb8acb649705786728e3b248", + "1": "d6cf995b.7f46b8bf.607187b5.f2573d69.ef9f7d82.f8890b3c.cd61fc56.7354dc7a.1e99c45f.7f46b8bf.7c3fa097.f2573d69.6f7f4efa.5fce695c.c0a0d45c.1ce8e212", + "identity": "126a3820-25bb-4f73-9910-bb8810c7042c" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 116, + "endLine": 116, + "startColumn": 21, + "endColumn": 27 + } + } + } + }, + { + "location": { + "id": 1, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 116, + "endLine": 116, + "startColumn": 21, + "endColumn": 27 + } + } + } + }, + { + "location": { + "id": 2, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 116, + "endLine": 116, + "startColumn": 17, + "endColumn": 27 + } + } + } + }, + { + "location": { + "id": 3, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 116, + "endLine": 116, + "startColumn": 17, + "endColumn": 30 + } + } + } + }, + { + "location": { + "id": 4, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 116, + "endLine": 116, + "startColumn": 8, + "endColumn": 16 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 828, + "priorityScoreFactors": [ + { + "label": true, + "type": "multipleOccurrence" + }, + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "javascript/NoSqli", + "ruleIndex": 1, + "level": "error", + "message": { + "text": "Unsanitized input from an HTTP parameter flows into findById, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.", + "markdown": "Unsanitized input from {0} {1} into {2}, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.", + "arguments": [ + "[an HTTP parameter](0)", + "[flows](1),(2),(3)", + "[findById](4)" + ] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 144, + "endLine": 144, + "startColumn": 8, + "endColumn": 16 + } + } + } + ], + "fingerprints": { + "0": "7411360805c50d8c4bc0bc5fd48895ca9355d0598b8aaa1f9a01476df07a3f83", + "1": "d6cf995b.7f46b8bf.607187b5.f2573d69.ef9f7d82.f8890b3c.cd61fc56.7354dc7a.1e99c45f.7f46b8bf.7c3fa097.f2573d69.6f7f4efa.5fce695c.c0a0d45c.1ce8e212", + "identity": "ef606779-f8c5-4346-97ff-5a9a6d4ef358" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 144, + "endLine": 144, + "startColumn": 21, + "endColumn": 27 + } + } + } + }, + { + "location": { + "id": 1, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 144, + "endLine": 144, + "startColumn": 21, + "endColumn": 27 + } + } + } + }, + { + "location": { + "id": 2, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 144, + "endLine": 144, + "startColumn": 17, + "endColumn": 27 + } + } + } + }, + { + "location": { + "id": 3, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 144, + "endLine": 144, + "startColumn": 17, + "endColumn": 30 + } + } + } + }, + { + "location": { + "id": 4, + "physicalLocation": { + "artifactLocation": { + "uri": "routes/index.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 144, + "endLine": 144, + "startColumn": 8, + "endColumn": 16 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 828, + "priorityScoreFactors": [ + { + "label": true, + "type": "multipleOccurrence" + }, + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + }, + "suppressions": [ + { + "justification": "Experimenting with consistent ignores capability. ", + "kind": "external", + "properties": { + "category": "temporary-ignore", + "expiration": "2025-02-11T23:00:00Z", + "ignoredOn": "2024-10-11T12:26:17.028Z", + "ignoredBy": { + "name": "Luke Watts", + "email": "luke@snyk.io" + } + } + } + ] + }, + { + "ruleId": "javascript/HardcodedNonCryptoSecret", + "ruleIndex": 2, + "level": "error", + "message": { + "text": "Avoid hardcoding values that are meant to be secret. Found a hardcoded string used in here.", + "markdown": "Avoid hardcoding values that are meant to be secret. Found {0} used in {1}.", + "arguments": ["[a hardcoded string](0)", "[here](1)"] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 74, + "endLine": 74, + "startColumn": 5, + "endColumn": 10 + } + } + } + ], + "fingerprints": { + "0": "a244acfe383de501ab67d46263a13b67af3e6eb8ef8f44f79cb9ff6f1ea8a851", + "1": "46b7c801.8e456e36.642d3d87.72a8f743.a46de81d.5fce695c.fee35010.89d75565.46b7c801.8e456e36.642d3d87.72a8f743.a46de81d.5fce695c.fee35010.89d75565", + "identity": "06c2fa18-2920-46fe-a838-66d276a171f0" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 74, + "endLine": 74, + "startColumn": 13, + "endColumn": 67 + } + } + } + }, + { + "location": { + "id": 1, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 74, + "endLine": 74, + "startColumn": 5, + "endColumn": 10 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 810, + "priorityScoreFactors": [ + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "javascript/DisablePoweredBy", + "ruleIndex": 3, + "level": "warning", + "message": { + "text": "Disable X-Powered-By header for your Express app (consider using Helmet middleware), because it exposes information about the used framework to potential attackers.", + "markdown": "Disable X-Powered-By header for your {0} (consider using Helmet middleware), because it exposes information about the used framework to potential attackers.", + "arguments": ["[Express app](0)"] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 31, + "endLine": 31, + "startColumn": 11, + "endColumn": 18 + } + } + } + ], + "fingerprints": { + "0": "11bbff3168402efa1154da12d7fa26f86f48501b097ca872c04bae6fe8c91c80", + "1": "ae77ea27.4773f344.607187b5.d7919eeb.a1fb1152.5fce695c.fee35010.89d75565.630e4ed1.4773f344.aa4dda5f.d7919eeb.f30fb760.49b28873.85bdc101.83642794", + "identity": "c2942d51-e62d-4d15-8ba4-a716e6368604" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 31, + "endLine": 31, + "startColumn": 11, + "endColumn": 18 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 560, + "priorityScoreFactors": [ + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + }, + "suppressions": [ + { + "justification": "", + "kind": "external", + "properties": { + "category": "not-vulnerable", + "ignoredOn": "2024-10-08T09:33:05.933Z", + "ignoredBy": { + "name": "JSON", + "email": "jason.luong@snyk.io" + } + } + } + ] + }, + { + "ruleId": "javascript/HttpToHttps", + "ruleIndex": 4, + "level": "warning", + "message": { + "text": "http.createServer uses HTTP which is an insecure protocol and should not be used in code due to cleartext transmission of information. Data in cleartext in a communication channel can be sniffed by unauthorized actors. Consider using the https module instead.", + "markdown": "{0} uses HTTP which is an insecure protocol and should not be used in code due to cleartext transmission of information. Data in cleartext in a communication channel can be sniffed by unauthorized actors. Consider using the https module instead.", + "arguments": ["[http.createServer](0)"] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 77, + "endLine": 77, + "startColumn": 1, + "endColumn": 18 + } + } + } + ], + "fingerprints": { + "0": "0910eae8edf827e1795e21e2a1722ba5d97e7b0a34c71f9620a04f51858c1247", + "1": "aac70831.4773f344.607187b5.9a6c48e6.2fce9a75.6f0d36d4.a4e722aa.b1b5c7cb.7a85a498.4773f344.d685e3e1.d7919eeb.8b312d3d.5fce695c.ea1fda40.89d75565", + "identity": "0fc278c9-0bfe-4bdd-b206-f107a17c0101" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 77, + "endLine": 77, + "startColumn": 1, + "endColumn": 18 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 560, + "priorityScoreFactors": [ + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "javascript/UseCsurfForExpress", + "ruleIndex": 5, + "level": "warning", + "message": { + "text": "CSRF protection is disabled for your Express app. This allows the attackers to execute requests on a user's behalf.", + "markdown": "CSRF protection is disabled for your {0}. This allows the attackers to execute requests on a user's behalf.", + "arguments": ["[Express app](0)"] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 31, + "endLine": 31, + "startColumn": 11, + "endColumn": 18 + } + } + } + ], + "fingerprints": { + "0": "e9efef11df29effdf12993c800f24b845901a11c4b123d7115a075c201c5acc2", + "1": "ae77ea27.4773f344.607187b5.d7919eeb.a1fb1152.5fce695c.fee35010.89d75565.630e4ed1.4773f344.aa4dda5f.d7919eeb.f30fb760.49b28873.85bdc101.83642794", + "identity": "a282b3ec-cbe1-4b5c-9b31-1caccaeaaa55" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "app.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 31, + "endLine": 31, + "startColumn": 11, + "endColumn": 18 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 560, + "priorityScoreFactors": [ + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "javascript/NoHardcodedPasswords", + "ruleIndex": 6, + "level": "warning", + "message": { + "text": "Do not hardcode passwords in code. Found hardcoded password used in password.", + "markdown": "Do not hardcode passwords in code. Found hardcoded password used in {0}.", + "arguments": ["[password](0)"] + }, + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "db.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 48, + "endLine": 48, + "startColumn": 35, + "endColumn": 43 + } + } + } + ], + "fingerprints": { + "0": "6e75768361e7b6592dcdc2667b17df3e12a1fa62a963d187774266b51729d4bc", + "1": "12567ef6.6d936dbf.bd65d204.fd94bb7c.79a7d027.fcf3002d.81d021f5.91c60b7d.12567ef6.6d936dbf.bd65d204.fd94bb7c.79a7d027.fcf3002d.81d021f5.91c60b7d", + "identity": "4b7c5f54-4850-4de8-9857-21c5a98e26eb" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "db.js", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 48, + "endLine": 48, + "startColumn": 35, + "endColumn": 43 + } + } + } + } + ] + } + ] + } + ], + "properties": { + "priorityScore": 510, + "priorityScoreFactors": [ + { + "label": true, + "type": "hotFileCodeFlow" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "snykPolicy/v1": { + "originalLevel": "warning", + "originalSeverity": "medium", + "severity": "low" + }, + "isAutofixable": false + } + } + ], + "properties": { + "coverage": [ + { + "files": 4, + "isSupported": true, + "lang": "EJS", + "type": "SUPPORTED" + }, + { + "files": 1, + "isSupported": true, + "lang": "HTML", + "type": "SUPPORTED" + }, + { + "files": 5, + "isSupported": true, + "lang": "JavaScript", + "type": "SUPPORTED" + } + ] + } + } + ] +} diff --git a/test/jest/acceptance/snyk-code/fixtures/test-sarif.json b/test/jest/acceptance/snyk-code/fixtures/test-sarif.json index 4a3c45d795..37138c4b4f 100644 --- a/test/jest/acceptance/snyk-code/fixtures/test-sarif.json +++ b/test/jest/acceptance/snyk-code/fixtures/test-sarif.json @@ -2679,6 +2679,7 @@ "suppressions": [ { "justification": "Experimenting with consistent ignores capability. ", + "kind": "external", "properties": { "category": "temporary-ignore", "expiration": "2025-02-11T23:00:00Z", @@ -2857,6 +2858,7 @@ "suppressions": [ { "justification": "", + "kind": "external", "properties": { "category": "not-vulnerable", "expiration": null, @@ -3087,6 +3089,11 @@ "type": "fixExamples" } ], + "snykPolicy/v1": { + "originalLevel": "warning", + "originalSeverity": "medium", + "severity": "low" + }, "isAutofixable": false }, "suppressions": null diff --git a/test/jest/acceptance/snyk-code/snyk-code.spec.ts b/test/jest/acceptance/snyk-code/snyk-code.spec.ts index a35166fdde..0a7864bd20 100644 --- a/test/jest/acceptance/snyk-code/snyk-code.spec.ts +++ b/test/jest/acceptance/snyk-code/snyk-code.spec.ts @@ -3,6 +3,7 @@ import { runSnykCLI } from '../../util/runSnykCLI'; import { fakeServer } from '../../../acceptance/fake-server'; import { fakeDeepCodeServer } from '../../../acceptance/deepcode-fake-server'; import { getServerPort } from '../../util/getServerPort'; +import { sortSarifByResults } from '../../util/sortSarif'; import { matchers } from 'jest-json-schema'; import { resolve } from 'path'; import { existsSync, unlinkSync } from 'fs'; @@ -118,7 +119,12 @@ describe('snyk code test', () => { }); it('should succeed with correct exit code - with sarif output', async () => { - const sarifPayload = require('./fixtures/test-sarif.json'); + let sarifPayload = require('./fixtures/test-sarif.json'); + // the golang implementation removes fields with value null from the sarif, + // so things like `"suppressions": null` need to be removed from the payload + if (type === 'golang/native') + sarifPayload = require('./fixtures/test-sarif-no-null-fields.json'); + server.setOrgSetting('sast', true); deepCodeServer.setCustomResponse({ configFiles: [], @@ -134,7 +140,7 @@ describe('snyk code test', () => { server.setSarifResponse(sarifPayload); - const { stderr, code } = await runSnykCLI( + const { stdout, stderr, code } = await runSnykCLI( `code test ${projectWithCodeIssues} --sarif`, { env: { @@ -148,10 +154,25 @@ describe('snyk code test', () => { expect(code).toBe(EXIT_CODE_ACTION_NEEDED); expect(stderr).toBe(''); + + let actualPayload; + expect(() => { + actualPayload = JSON.parse(stdout); + }).not.toThrow(); + + const sortedActualPayload = sortSarifByResults(actualPayload); + const sortedSarifPayload = sortSarifByResults(sarifPayload); + + expect(sortedActualPayload).toEqual(sortedSarifPayload); }); it('should succeed with correct exit code - with json output', async () => { - const sarifPayload = require('./fixtures/test-sarif.json'); + let sarifPayload = require('./fixtures/test-sarif.json'); + // the golang implementation removes fields with value null from the sarif, + // so things like `"suppressions": null` need to be removed from the payload + if (type === 'golang/native') + sarifPayload = require('./fixtures/test-sarif-no-null-fields.json'); + server.setOrgSetting('sast', true); deepCodeServer.setFiltersResponse({ configFiles: [], @@ -166,7 +187,7 @@ describe('snyk code test', () => { }); server.setSarifResponse(sarifPayload); - const { stderr, code } = await runSnykCLI( + const { stdout, stderr, code } = await runSnykCLI( `code test ${projectWithCodeIssues} --json`, { env: { @@ -180,10 +201,22 @@ describe('snyk code test', () => { expect(stderr).toBe(''); expect(code).toBe(EXIT_CODE_ACTION_NEEDED); + + let actualPayload; + expect(() => { + actualPayload = JSON.parse(stdout); + }).not.toThrow(); + + + const sortedActualPayload = sortSarifByResults(actualPayload); + const sortedSarifPayload = sortSarifByResults(sarifPayload); + + expect(sortedActualPayload).toEqual(sortedSarifPayload); }); it('should succeed with correct exit code - normal output', async () => { const sarifPayload = require('./fixtures/test-sarif.json'); + server.setOrgSetting('sast', true); deepCodeServer.setFiltersResponse({ configFiles: [], diff --git a/test/jest/util/sortSarif.ts b/test/jest/util/sortSarif.ts new file mode 100644 index 0000000000..b12353cb0b --- /dev/null +++ b/test/jest/util/sortSarif.ts @@ -0,0 +1,11 @@ +export function sortSarifByResults(sarifPayload) { + sarifPayload.runs[0].results = sarifPayload.runs[0].results.sort( + (a, b) => { + return a.fingerprints.identity.localeCompare( + b.fingerprints.identity, + ); + }, + ); + + return sarifPayload +}