Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion change-notes/1.20/analysis-javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

| **Query** | **Tags** | **Purpose** |
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Arbitrary file write during archive extraction ("Zip Slip") (`js/zipslip`) | security, external/cwe/cwe-022 | Identifies extraction routines that allow arbitrary file overwrite vulnerabilities. Results are hidden on LGTM by default. |
| Arrow method on Vue instance (`js/vue/arrow-method-on-vue-instance`) | reliability, frameworks/vue | Highlights arrow functions that are used as methods on Vue instances. Results are shown on LGTM by default.|
| Cross-window communication with unrestricted target origin (`js/cross-window-information-leak`) | security, external/cwe/201, external/cwe/359 | Highlights code that sends potentially sensitive information to another window without restricting the receiver window's origin, indicating a possible violation of [CWE-201](https://cwe.mitre.org/data/definitions/201.html). Results are shown on LGTM by default. |
| Double escaping or unescaping (`js/double-escaping`) | correctness, security, external/cwe/cwe-116 | Highlights potential double escaping or unescaping of special characters, indicating a possible violation of [CWE-116](https://cwe.mitre.org/data/definitions/116.html). Results are shown on LGTM by default. |
Expand Down Expand Up @@ -55,7 +56,7 @@
| Useless assignment to property. | Fewer false-positive results | This rule now treats assignments with complex right-hand sides correctly. |
| Unsafe dynamic method access | Fewer false-positive results | This rule no longer flags concatenated strings as unsafe method names. |
| Unvalidated dynamic method call | More true-positive results | This rule now flags concatenated strings as unvalidated method names in more cases. |
| Useless conditional | More true-positive results | This rule now flags additional uses of function call values. |
| Useless conditional | More true-positive results | This rule now flags additional uses of function call values. |

## Changes to QL libraries

Expand Down
14 changes: 14 additions & 0 deletions javascript/ql/src/semmle/javascript/security/dataflow/ZipSlip.qll
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ module ZipSlip {
*/
abstract class Sink extends DataFlow::Node { }

/**
* A sanitizer for unsafe zip extraction.
*/
abstract class Sanitizer extends DataFlow::Node { }

/**
* A sanitizer guard for unsafe zip extraction.
*/
Expand All @@ -28,6 +33,8 @@ module ZipSlip {

override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }

override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer }

override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode nd) {
nd instanceof SanitizerGuard
}
Expand Down Expand Up @@ -90,6 +97,13 @@ module ZipSlip {
FileSystemWriteSink() { exists(FileSystemWriteAccess fsw | fsw.getAPathArgument() = this) }
}

/** An expression that sanitizes by calling path.basename */
class BasenameSanitizer extends Sanitizer {
BasenameSanitizer() {
this = DataFlow::moduleImport("path").getAMemberCall("basename")
}
}

/**
* Gets a string which is sufficient to exclude to make
* a filepath definitely not refer to parent directories.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const fs = require('fs');
const unzip = require('unzip');
const path = require('path');

fs.createReadStream('archive.zip')
.pipe(unzip.Parse())
.on('entry', entry => {
const fileName = entry.path;
entry.pipe(fs.createWriteStream(path.join('my_directory', path.basename(fileName))));
});