Merge pull request #4566 from asgerf/js/classnames

Approved by erik-krogh
This commit is contained in:
CodeQL CI
2020-10-29 11:00:06 +00:00
committed by GitHub
6 changed files with 172 additions and 0 deletions

View File

@@ -11,6 +11,8 @@
- [debounce](https://www.npmjs.com/package/debounce)
- [bluebird](https://www.npmjs.com/package/bluebird)
- [call-limit](https://www.npmjs.com/package/call-limit)
- [classnames](https://www.npmjs.com/package/classnames)
- [clsx](https://www.npmjs.com/package/clsx)
- [express](https://www.npmjs.com/package/express)
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)
- [fast-safe-stringify](https://www.npmjs.com/package/fast-safe-stringify)

View File

@@ -73,6 +73,7 @@ import semmle.javascript.frameworks.Azure
import semmle.javascript.frameworks.Babel
import semmle.javascript.frameworks.Cheerio
import semmle.javascript.frameworks.ComposedFunctions
import semmle.javascript.frameworks.Classnames
import semmle.javascript.frameworks.ClientRequests
import semmle.javascript.frameworks.ClosureLibrary
import semmle.javascript.frameworks.CookieLibraries

View File

@@ -0,0 +1,39 @@
/**
* Provides taint steps modeling flow through the `classnames` and `clsx` libraries.
*/
import javascript
private DataFlow::SourceNode classnames() {
result = DataFlow::moduleImport(["classnames", "classnames/dedupe", "classnames/bind"])
}
private class PlainStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
PlainStep() {
this = classnames().getACall()
or
this = DataFlow::moduleImport("clsx").getACall()
}
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = getAnArgument() and
succ = this
}
}
/**
* Step from `x` or `y` to the result of `classnames.bind(x)(y)`.
*/
private class BindStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
DataFlow::CallNode bind;
BindStep() {
bind = classnames().getAMemberCall("bind") and
this = bind.getACall()
}
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = [getAnArgument(), bind.getAnArgument(), bind.getOptionArgument(_, _)] and
succ = this
}
}

View File

@@ -59,6 +59,36 @@ nodes
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') |
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') |
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') |
| classnames.js:7:31:7:84 | `<span ... <span>` |
| classnames.js:7:31:7:84 | `<span ... <span>` |
| classnames.js:7:47:7:69 | classNa ... w.name) |
| classnames.js:7:58:7:68 | window.name |
| classnames.js:7:58:7:68 | window.name |
| classnames.js:8:31:8:85 | `<span ... <span>` |
| classnames.js:8:31:8:85 | `<span ... <span>` |
| classnames.js:8:47:8:70 | classNa ... w.name) |
| classnames.js:8:59:8:69 | window.name |
| classnames.js:8:59:8:69 | window.name |
| classnames.js:9:31:9:85 | `<span ... <span>` |
| classnames.js:9:31:9:85 | `<span ... <span>` |
| classnames.js:9:47:9:70 | classNa ... w.name) |
| classnames.js:9:59:9:69 | window.name |
| classnames.js:9:59:9:69 | window.name |
| classnames.js:10:45:10:55 | window.name |
| classnames.js:10:45:10:55 | window.name |
| classnames.js:11:31:11:79 | `<span ... <span>` |
| classnames.js:11:31:11:79 | `<span ... <span>` |
| classnames.js:11:47:11:64 | unsafeStyle('foo') |
| classnames.js:13:31:13:83 | `<span ... <span>` |
| classnames.js:13:31:13:83 | `<span ... <span>` |
| classnames.js:13:47:13:68 | safeSty ... w.name) |
| classnames.js:13:57:13:67 | window.name |
| classnames.js:13:57:13:67 | window.name |
| classnames.js:15:31:15:78 | `<span ... <span>` |
| classnames.js:15:31:15:78 | `<span ... <span>` |
| classnames.js:15:47:15:63 | clsx(window.name) |
| classnames.js:15:52:15:62 | window.name |
| classnames.js:15:52:15:62 | window.name |
| jquery.js:2:7:2:40 | tainted |
| jquery.js:2:7:2:40 | tainted |
| jquery.js:2:17:2:33 | document.location |
@@ -601,6 +631,30 @@ edges
| angular2-client.ts:35:44:35:89 | this.ro ... .params | angular2-client.ts:35:44:35:91 | this.ro ... arams.x |
| angular2-client.ts:37:44:37:58 | this.router.url | angular2-client.ts:37:44:37:58 | this.router.url |
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') | angular2-client.ts:41:44:41:76 | routeSn ... ('foo') |
| classnames.js:7:47:7:69 | classNa ... w.name) | classnames.js:7:31:7:84 | `<span ... <span>` |
| classnames.js:7:47:7:69 | classNa ... w.name) | classnames.js:7:31:7:84 | `<span ... <span>` |
| classnames.js:7:58:7:68 | window.name | classnames.js:7:47:7:69 | classNa ... w.name) |
| classnames.js:7:58:7:68 | window.name | classnames.js:7:47:7:69 | classNa ... w.name) |
| classnames.js:8:47:8:70 | classNa ... w.name) | classnames.js:8:31:8:85 | `<span ... <span>` |
| classnames.js:8:47:8:70 | classNa ... w.name) | classnames.js:8:31:8:85 | `<span ... <span>` |
| classnames.js:8:59:8:69 | window.name | classnames.js:8:47:8:70 | classNa ... w.name) |
| classnames.js:8:59:8:69 | window.name | classnames.js:8:47:8:70 | classNa ... w.name) |
| classnames.js:9:47:9:70 | classNa ... w.name) | classnames.js:9:31:9:85 | `<span ... <span>` |
| classnames.js:9:47:9:70 | classNa ... w.name) | classnames.js:9:31:9:85 | `<span ... <span>` |
| classnames.js:9:59:9:69 | window.name | classnames.js:9:47:9:70 | classNa ... w.name) |
| classnames.js:9:59:9:69 | window.name | classnames.js:9:47:9:70 | classNa ... w.name) |
| classnames.js:10:45:10:55 | window.name | classnames.js:11:47:11:64 | unsafeStyle('foo') |
| classnames.js:10:45:10:55 | window.name | classnames.js:11:47:11:64 | unsafeStyle('foo') |
| classnames.js:11:47:11:64 | unsafeStyle('foo') | classnames.js:11:31:11:79 | `<span ... <span>` |
| classnames.js:11:47:11:64 | unsafeStyle('foo') | classnames.js:11:31:11:79 | `<span ... <span>` |
| classnames.js:13:47:13:68 | safeSty ... w.name) | classnames.js:13:31:13:83 | `<span ... <span>` |
| classnames.js:13:47:13:68 | safeSty ... w.name) | classnames.js:13:31:13:83 | `<span ... <span>` |
| classnames.js:13:57:13:67 | window.name | classnames.js:13:47:13:68 | safeSty ... w.name) |
| classnames.js:13:57:13:67 | window.name | classnames.js:13:47:13:68 | safeSty ... w.name) |
| classnames.js:15:47:15:63 | clsx(window.name) | classnames.js:15:31:15:78 | `<span ... <span>` |
| classnames.js:15:47:15:63 | clsx(window.name) | classnames.js:15:31:15:78 | `<span ... <span>` |
| classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) |
| classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) |
| jquery.js:2:7:2:40 | tainted | jquery.js:7:20:7:26 | tainted |
| jquery.js:2:7:2:40 | tainted | jquery.js:8:28:8:34 | tainted |
| jquery.js:2:17:2:33 | document.location | jquery.js:2:17:2:40 | documen ... .search |
@@ -1063,6 +1117,12 @@ edges
| angular2-client.ts:35:44:35:91 | this.ro ... arams.x | angular2-client.ts:35:44:35:89 | this.ro ... .params | angular2-client.ts:35:44:35:91 | this.ro ... arams.x | Cross-site scripting vulnerability due to $@. | angular2-client.ts:35:44:35:89 | this.ro ... .params | user-provided value |
| angular2-client.ts:37:44:37:58 | this.router.url | angular2-client.ts:37:44:37:58 | this.router.url | angular2-client.ts:37:44:37:58 | this.router.url | Cross-site scripting vulnerability due to $@. | angular2-client.ts:37:44:37:58 | this.router.url | user-provided value |
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') | angular2-client.ts:41:44:41:76 | routeSn ... ('foo') | angular2-client.ts:41:44:41:76 | routeSn ... ('foo') | Cross-site scripting vulnerability due to $@. | angular2-client.ts:41:44:41:76 | routeSn ... ('foo') | user-provided value |
| classnames.js:7:31:7:84 | `<span ... <span>` | classnames.js:7:58:7:68 | window.name | classnames.js:7:31:7:84 | `<span ... <span>` | Cross-site scripting vulnerability due to $@. | classnames.js:7:58:7:68 | window.name | user-provided value |
| classnames.js:8:31:8:85 | `<span ... <span>` | classnames.js:8:59:8:69 | window.name | classnames.js:8:31:8:85 | `<span ... <span>` | Cross-site scripting vulnerability due to $@. | classnames.js:8:59:8:69 | window.name | user-provided value |
| classnames.js:9:31:9:85 | `<span ... <span>` | classnames.js:9:59:9:69 | window.name | classnames.js:9:31:9:85 | `<span ... <span>` | Cross-site scripting vulnerability due to $@. | classnames.js:9:59:9:69 | window.name | user-provided value |
| classnames.js:11:31:11:79 | `<span ... <span>` | classnames.js:10:45:10:55 | window.name | classnames.js:11:31:11:79 | `<span ... <span>` | Cross-site scripting vulnerability due to $@. | classnames.js:10:45:10:55 | window.name | user-provided value |
| classnames.js:13:31:13:83 | `<span ... <span>` | classnames.js:13:57:13:67 | window.name | classnames.js:13:31:13:83 | `<span ... <span>` | Cross-site scripting vulnerability due to $@. | classnames.js:13:57:13:67 | window.name | user-provided value |
| classnames.js:15:31:15:78 | `<span ... <span>` | classnames.js:15:52:15:62 | window.name | classnames.js:15:31:15:78 | `<span ... <span>` | Cross-site scripting vulnerability due to $@. | classnames.js:15:52:15:62 | window.name | user-provided value |
| jquery.js:7:5:7:34 | "<div i ... + "\\">" | jquery.js:2:17:2:40 | documen ... .search | jquery.js:7:5:7:34 | "<div i ... + "\\">" | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:40 | documen ... .search | user-provided value |
| jquery.js:8:18:8:34 | "XSS: " + tainted | jquery.js:2:17:2:33 | document.location | jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |
| jquery.js:10:5:10:40 | "<b>" + ... "</b>" | jquery.js:10:13:10:20 | location | jquery.js:10:5:10:40 | "<b>" + ... "</b>" | Cross-site scripting vulnerability due to $@. | jquery.js:10:13:10:20 | location | user-provided value |

View File

@@ -59,6 +59,36 @@ nodes
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') |
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') |
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') |
| classnames.js:7:31:7:84 | `<span ... <span>` |
| classnames.js:7:31:7:84 | `<span ... <span>` |
| classnames.js:7:47:7:69 | classNa ... w.name) |
| classnames.js:7:58:7:68 | window.name |
| classnames.js:7:58:7:68 | window.name |
| classnames.js:8:31:8:85 | `<span ... <span>` |
| classnames.js:8:31:8:85 | `<span ... <span>` |
| classnames.js:8:47:8:70 | classNa ... w.name) |
| classnames.js:8:59:8:69 | window.name |
| classnames.js:8:59:8:69 | window.name |
| classnames.js:9:31:9:85 | `<span ... <span>` |
| classnames.js:9:31:9:85 | `<span ... <span>` |
| classnames.js:9:47:9:70 | classNa ... w.name) |
| classnames.js:9:59:9:69 | window.name |
| classnames.js:9:59:9:69 | window.name |
| classnames.js:10:45:10:55 | window.name |
| classnames.js:10:45:10:55 | window.name |
| classnames.js:11:31:11:79 | `<span ... <span>` |
| classnames.js:11:31:11:79 | `<span ... <span>` |
| classnames.js:11:47:11:64 | unsafeStyle('foo') |
| classnames.js:13:31:13:83 | `<span ... <span>` |
| classnames.js:13:31:13:83 | `<span ... <span>` |
| classnames.js:13:47:13:68 | safeSty ... w.name) |
| classnames.js:13:57:13:67 | window.name |
| classnames.js:13:57:13:67 | window.name |
| classnames.js:15:31:15:78 | `<span ... <span>` |
| classnames.js:15:31:15:78 | `<span ... <span>` |
| classnames.js:15:47:15:63 | clsx(window.name) |
| classnames.js:15:52:15:62 | window.name |
| classnames.js:15:52:15:62 | window.name |
| jquery.js:2:7:2:40 | tainted |
| jquery.js:2:7:2:40 | tainted |
| jquery.js:2:17:2:33 | document.location |
@@ -605,6 +635,30 @@ edges
| angular2-client.ts:35:44:35:89 | this.ro ... .params | angular2-client.ts:35:44:35:91 | this.ro ... arams.x |
| angular2-client.ts:37:44:37:58 | this.router.url | angular2-client.ts:37:44:37:58 | this.router.url |
| angular2-client.ts:41:44:41:76 | routeSn ... ('foo') | angular2-client.ts:41:44:41:76 | routeSn ... ('foo') |
| classnames.js:7:47:7:69 | classNa ... w.name) | classnames.js:7:31:7:84 | `<span ... <span>` |
| classnames.js:7:47:7:69 | classNa ... w.name) | classnames.js:7:31:7:84 | `<span ... <span>` |
| classnames.js:7:58:7:68 | window.name | classnames.js:7:47:7:69 | classNa ... w.name) |
| classnames.js:7:58:7:68 | window.name | classnames.js:7:47:7:69 | classNa ... w.name) |
| classnames.js:8:47:8:70 | classNa ... w.name) | classnames.js:8:31:8:85 | `<span ... <span>` |
| classnames.js:8:47:8:70 | classNa ... w.name) | classnames.js:8:31:8:85 | `<span ... <span>` |
| classnames.js:8:59:8:69 | window.name | classnames.js:8:47:8:70 | classNa ... w.name) |
| classnames.js:8:59:8:69 | window.name | classnames.js:8:47:8:70 | classNa ... w.name) |
| classnames.js:9:47:9:70 | classNa ... w.name) | classnames.js:9:31:9:85 | `<span ... <span>` |
| classnames.js:9:47:9:70 | classNa ... w.name) | classnames.js:9:31:9:85 | `<span ... <span>` |
| classnames.js:9:59:9:69 | window.name | classnames.js:9:47:9:70 | classNa ... w.name) |
| classnames.js:9:59:9:69 | window.name | classnames.js:9:47:9:70 | classNa ... w.name) |
| classnames.js:10:45:10:55 | window.name | classnames.js:11:47:11:64 | unsafeStyle('foo') |
| classnames.js:10:45:10:55 | window.name | classnames.js:11:47:11:64 | unsafeStyle('foo') |
| classnames.js:11:47:11:64 | unsafeStyle('foo') | classnames.js:11:31:11:79 | `<span ... <span>` |
| classnames.js:11:47:11:64 | unsafeStyle('foo') | classnames.js:11:31:11:79 | `<span ... <span>` |
| classnames.js:13:47:13:68 | safeSty ... w.name) | classnames.js:13:31:13:83 | `<span ... <span>` |
| classnames.js:13:47:13:68 | safeSty ... w.name) | classnames.js:13:31:13:83 | `<span ... <span>` |
| classnames.js:13:57:13:67 | window.name | classnames.js:13:47:13:68 | safeSty ... w.name) |
| classnames.js:13:57:13:67 | window.name | classnames.js:13:47:13:68 | safeSty ... w.name) |
| classnames.js:15:47:15:63 | clsx(window.name) | classnames.js:15:31:15:78 | `<span ... <span>` |
| classnames.js:15:47:15:63 | clsx(window.name) | classnames.js:15:31:15:78 | `<span ... <span>` |
| classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) |
| classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) |
| jquery.js:2:7:2:40 | tainted | jquery.js:7:20:7:26 | tainted |
| jquery.js:2:7:2:40 | tainted | jquery.js:8:28:8:34 | tainted |
| jquery.js:2:17:2:33 | document.location | jquery.js:2:17:2:40 | documen ... .search |

View File

@@ -0,0 +1,16 @@
import classNames from 'classnames';
import classNamesD from 'classnames/dedupe';
import classNamesB from 'classnames/bind';
import clsx from 'clsx';
function main() {
document.body.innerHTML = `<span class="${classNames(window.name)}">Hello<span>`; // NOT OK
document.body.innerHTML = `<span class="${classNamesD(window.name)}">Hello<span>`; // NOT OK
document.body.innerHTML = `<span class="${classNamesB(window.name)}">Hello<span>`; // NOT OK
let unsafeStyle = classNames.bind({foo: window.name});
document.body.innerHTML = `<span class="${unsafeStyle('foo')}">Hello<span>`; // NOT OK
let safeStyle = classNames.bind({});
document.body.innerHTML = `<span class="${safeStyle(window.name)}">Hello<span>`; // NOT OK
document.body.innerHTML = `<span class="${safeStyle('foo')}">Hello<span>`; // OK
document.body.innerHTML = `<span class="${clsx(window.name)}">Hello<span>`; // NOT OK
}