Merge master into next.

This commit is contained in:
Aditya Sharad
2018-12-13 17:57:31 +00:00
54 changed files with 515 additions and 133 deletions

View File

@@ -4,7 +4,11 @@
* Support for popular libraries has been improved. Consequently, queries may produce more results on code bases that use the following features:
- client-side code, for example [React](https://reactjs.org/)
- cookies and webstorage, for example [js-cookie](https://github.com/js-cookie/js-cookie)
- server-side code, for example [hapi](https://hapijs.com/)
* File classification has been improved to recognize additional generated files, for example files from [HTML Tidy](html-tidy.org).
* The taint tracking library now recognizes flow through persistent storage, this may give more results for the security queries.
## New queries
@@ -20,6 +24,7 @@
| **Query** | **Expected impact** | **Change** |
|--------------------------------------------|------------------------------|------------------------------------------------------------------------------|
| Client-side cross-site scripting | More results | This rule now recognizes WinJS functions that are vulnerable to HTML injection. |
| Insecure randomness | More results | This rule now flags insecure uses of `crypto.pseudoRandomBytes`. |
| Unused parameter | Fewer false-positive results | This rule no longer flags parameters with leading underscore. |
| Unused variable, import, function or class | Fewer false-positive results | This rule now flags fewer variables that are implictly used by JSX elements, and no longer flags variables with leading underscore. |

View File

@@ -1 +0,0 @@
<queries language="cpp"/>

View File

@@ -34,11 +34,5 @@ private predicate readsEnvironment(Expr read, string sourceDescription) {
read = call and
call.getTarget().hasGlobalName(name) and
(name = "getenv" or name = "secure_getenv" or name = "_wgetenv") and
sourceDescription = name) or
exists(MessageExpr getObjectKey, MessageExpr getEnviron |
read = getObjectKey and
getObjectKey.getTarget().getQualifiedName().matches("NSDictionary%::-objectForKey:") and
getObjectKey.getQualifier() = getEnviron and
getEnviron.getTarget().getQualifiedName().matches("NSProcessInfo%:-environment") and
sourceDescription = "NSProcessInfo")
sourceDescription = name)
}

View File

@@ -203,18 +203,5 @@ predicate shellCommand(Expr command, string callChain) {
and arrayInitializer.getChild(idx) = command
and shellCommandPreface(commandInterpreter.getValue(), flag.getValue())
and idx > 1)
// Creation of NSTask
or exists(
MessageExpr launchedTaskCall, TextLiteral commandInterpreter,
Expr arrayLiteral, TextLiteral flag
|
launchedTaskCall.getStaticTarget().getQualifiedName().matches("NSTask%::+launchedTaskWithLaunchPath:arguments:")
and commandInterpreter = launchedTaskCall.getArgument(0)
and arrayLiteral = launchedTaskCall.getArgument(1)
and arrayElement(arrayLiteral, 0, flag)
and arrayElement(arrayLiteral, 1, command)
and shellCommandPreface(commandInterpreter.getValue(), flag.getValue())
and callChain = "NSTask")
}

View File

@@ -35,25 +35,3 @@ class SensitiveCall extends SensitiveExpr {
)
}
}
class SensitivePropAccess extends SensitiveExpr {
SensitivePropAccess() {
exists (PropertyAccess acc, string name |
acc = this and
name = acc.getProperty().getName().toLowerCase() and
name.matches(suspicious()) and
not name.matches(nonSuspicious()))
}
}
/**
* A read from the value of a text widget.
*/
class SensitiveTextRead extends SensitiveExpr {
SensitiveTextRead() {
exists (PropertyAccess facc |
facc = this and
facc.getReceiver() instanceof SensitiveExpr and
facc.getProperty().getName() = "text")
}
}

View File

@@ -238,21 +238,12 @@ predicate insideFunctionValueMoveTo(Element src, Element dest)
returnArgument(c.getTarget(), sourceArg)
and src = c.getArgument(sourceArg)
and dest = c)
or exists (MessageExpr send |
methodReturningAnyArgument(send.getStaticTarget())
and not send instanceof FormattingFunctionCall
and src = send.getAnArgument()
and dest = send)
or exists(FormattingFunctionCall formattingSend, int arg, FormatLiteral format, string argFormat |
dest = formattingSend
and formattingSend.getArgument(arg) = src
and format = formattingSend.getFormat()
and format.getConversionChar(arg - formattingSend.getTarget().getNumberOfParameters()) = argFormat
and (argFormat = "s" or argFormat = "S" or argFormat = "@"))
or exists (ExprMessageExpr send |
methodReturningReceiver(send.getStaticTarget())
and src = send.getReceiver()
and dest = send)
// Expressions computed from tainted data are also tainted
or (exists (FunctionCall call | dest = call and isPureFunction(call.getTarget().getName()) |
call.getAnArgument() = src
@@ -457,60 +448,6 @@ private predicate returnArgument(Function f, int sourceArg)
or (f.hasGlobalName("gethostbyaddr") and sourceArg = 0)
}
/** A method where if any argument is tainted, the return value should be, too */
private predicate methodReturningAnyArgument(MemberFunction method) {
method.getQualifiedName().matches("NS%Array%::+array%") or
method.getQualifiedName().matches("NS%Array%::-arrayBy%") or
method.getQualifiedName().matches("NS%Array%::-componentsJoinedByString:") or
method.getQualifiedName().matches("NS%Array%::-init%") or
method.getQualifiedName().matches("NS%Data%::+dataWith%") or
method.getQualifiedName().matches("NS%Data%::-initWith%") or
method.getQualifiedName().matches("NS%String%::+pathWithComponents:") or
method.getQualifiedName().matches("NS%String%::+stringWith%") or
method.getQualifiedName().matches("NS%String%::-initWithCString:") or
method.getQualifiedName().matches("NS%String%::-initWithCString:length:") or
method.getQualifiedName().matches("NS%String%::-initWithCStringNoCopy:length:") or
method.getQualifiedName().matches("NS%String%::-initWithCharacters:length:") or
method.getQualifiedName().matches("NS%String%::-initWithCharactersNoCopy:length:freeWhenDone:") or
method.getQualifiedName().matches("NS%String%::-initWithFormat:") or
method.getQualifiedName().matches("NS%String%::-initWithFormat:arguments:") or
method.getQualifiedName().matches("NS%String%::-initWithString:") or
method.getQualifiedName().matches("NS%String%::-initWithUTF8String:") or
method.getQualifiedName().matches("NS%String%::-stringByAppendingFormat:") or
method.getQualifiedName().matches("NS%String%::-stringByAppendingString:") or
method.getQualifiedName().matches("NS%String%::-stringByPaddingToLength:withString:startingAtIndex:") or
method.getQualifiedName().matches("NS%String%::-stringByReplacing%") or
method.getQualifiedName().matches("NS%String%::-stringsByAppendingPaths:")
}
/** A method where if the receiver is tainted, the return value should be, too */
private predicate methodReturningReceiver(MemberFunction method) {
method.getQualifiedName().matches("NS%Array%::-arrayBy%") or
method.getQualifiedName().matches("NS%Array%::-componentsJoinedByString:") or
method.getQualifiedName().matches("NS%Array%::-firstObject") or
method.getQualifiedName().matches("NS%Array%::-lastObject") or
method.getQualifiedName().matches("NS%Array%::-objectAt%") or
method.getQualifiedName().matches("NS%Array%::-pathsMatchingExtensions:") or
method.getQualifiedName().matches("NS%Array%::-sortedArray%") or
method.getQualifiedName().matches("NS%Array%::-subarrayWithRange:") or
method.getQualifiedName().matches("NS%Data%::-bytes") or
method.getQualifiedName().matches("NS%Data%::-subdataWithRange:") or
method.getQualifiedName().matches("NS%String%::-capitalizedString%") or
method.getQualifiedName().matches("NS%String%::-componentsSeparatedByCharactersInSet:") or
method.getQualifiedName().matches("NS%String%::-componentsSeparatedByString:") or
method.getQualifiedName().matches("NS%String%::-cStringUsingEncoding:") or
method.getQualifiedName().matches("NS%String%::-dataUsingEncoding:%") or
method.getQualifiedName().matches("NS%String%::-lowercaseString%") or
method.getQualifiedName().matches("NS%String%::-pathComponents") or
method.getQualifiedName().matches("NS%String%::-stringBy%") or
method.getQualifiedName().matches("NS%String%::-stringsByAppendingPaths:") or
method.getQualifiedName().matches("NS%String%::-substringFromIndex:") or
method.getQualifiedName().matches("NS%String%::-substringToIndex:") or
method.getQualifiedName().matches("NS%String%::-substringWithRange:") or
method.getQualifiedName().matches("NS%String%::-uppercaseString%") or
method.getQualifiedName().matches("NS%String%::-UTF8String")
}
/**
* Resolve potential target function(s) for `call`.
*

View File

@@ -118,8 +118,9 @@ class ExplicitUpcast extends ExplicitCast {
}
pragma [nomagic]
private predicate isDisambiguatingStaticCall0(StaticCall c, StaticCallable target, ValueOrRefType t) {
private predicate isDisambiguatingStaticCall0(StaticCall c, StaticCallable target, string name, ValueOrRefType t) {
this.isArgument(c, target) and
name = target.getName() and
(
t = c.(QualifiableExpr).getQualifier().getType()
or
@@ -131,9 +132,9 @@ class ExplicitUpcast extends ExplicitCast {
/** Holds if this upcast may be used to disambiguate the target of a static call. */
pragma [nomagic]
private predicate isDisambiguatingStaticCall(StaticCallable other, int args) {
exists(StaticCall c, StaticCallable target, ValueOrRefType t |
this.isDisambiguatingStaticCall0(c, target, t) |
hasStaticCallable(t, other, target.getName()) and
exists(StaticCall c, StaticCallable target, ValueOrRefType t, string name |
this.isDisambiguatingStaticCall0(c, target, name, t) |
hasStaticCallable(t, other, name) and
args = c.getNumberOfArguments() and
other != target
)

View File

@@ -25,7 +25,7 @@ string metachar() {
string getAMatchedString(Expr e) {
result = getAMatchedConstant(e.(RegExpLiteral).getRoot()).getValue()
or
result = e.(StringLiteral).getValue()
result = e.getStringValue()
}
/** Gets a constant matched by `t`. */

View File

@@ -60,6 +60,7 @@ import semmle.javascript.frameworks.Azure
import semmle.javascript.frameworks.Babel
import semmle.javascript.frameworks.ComposedFunctions
import semmle.javascript.frameworks.ClientRequests
import semmle.javascript.frameworks.CookieLibraries
import semmle.javascript.frameworks.Credentials
import semmle.javascript.frameworks.CryptoLibraries
import semmle.javascript.frameworks.DigitalOcean

View File

@@ -65,3 +65,27 @@ abstract class DatabaseAccess extends DataFlow::Node {
/** Gets an argument to this database access that is interpreted as a query. */
abstract DataFlow::Node getAQueryArgument();
}
/**
* A data flow node that reads persistent data.
*/
abstract class PersistentReadAccess extends DataFlow::Node {
/**
* Gets a corresponding persistent write, if any.
*/
abstract PersistentWriteAccess getAWrite();
}
/**
* A data flow node that writes persistent data.
*/
abstract class PersistentWriteAccess extends DataFlow::Node {
/**
* Gets the data flow node corresponding to the written value.
*/
abstract DataFlow::Node getValue();
}

View File

@@ -42,8 +42,8 @@ class CodeGeneratorMarkerComment extends GeneratedCodeMarkerComment {
*/
private predicate codeGeneratorMarkerComment(Comment c, string tool) {
exists (string toolPattern |
toolPattern = "js_of_ocaml|CoffeeScript|LiveScript|dart2js|ANTLR|PEG\\.js|Opal|JSX|jison(?:-lex)?" and
tool = c.getText().regexpCapture("(?s)[\\s*]*(?:parser )?[gG]eneratedy? (?:from .*)?by (" + toolPattern + ")\\b.*", 1)
toolPattern = "js_of_ocaml|CoffeeScript|LiveScript|dart2js|ANTLR|PEG\\.js|Opal|JSX|jison(?:-lex)?|(?:Microsoft \\(R\\) AutoRest Code Generator)|purs" and
tool = c.getText().regexpCapture("(?s)[\\s*]*(?:parser |Code )?[gG]eneratedy? (?:from .*)?by (" + toolPattern + ")\\b.*", 1)
)
}
@@ -114,6 +114,17 @@ private predicate isData(File f) {
)
}
/**
* Holds if `f` is a generated HTML file.
*/
private predicate isGeneratedHtml(File f) {
exists(HTML::Element e |
e.getFile() = f and
e.getName() = "meta" and
e.getAttributeByName("name").getValue() = "generator"
)
}
/**
* Holds if `tl` looks like it contains generated code.
*/
@@ -124,12 +135,14 @@ predicate isGenerated(TopLevel tl) {
tl instanceof DartGeneratedTopLevel or
exists (GeneratedCodeMarkerComment gcmc | tl = gcmc.getTopLevel()) or
hasManyInvocations(tl) or
isData(tl.getFile())
isData(tl.getFile()) or
isGeneratedHtml(tl.getFile())
}
/**
* Holds if `file` look like it contains generated code.
*/
predicate isGeneratedCode(File file) {
isGenerated(file.getATopLevel())
isGenerated(file.getATopLevel()) or
isGeneratedHtml(file)
}

View File

@@ -232,6 +232,24 @@ module TaintTracking {
}
}
/**
* A taint propagating data flow edge through persistent storage.
*/
private class StorageTaintStep extends AdditionalTaintStep {
PersistentReadAccess read;
StorageTaintStep() {
this = read
}
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = read.getAWrite().getValue() and
succ = read
}
}
/**
* A taint propagating data flow edge caused by the builtin array functions.
*/

View File

@@ -222,10 +222,10 @@ predicate isMultiLicenseBundle(TopLevel tl) {
)
) > 1
or
// case: ordinary block comments with "@license" lines
// case: ordinary block comments lines that start with a license
count(BlockComment head |
head.getTopLevel() = tl and
head.getLine(_).regexpMatch("(?i) *\\* @license .*")
head.getLine(_).regexpMatch("(?i)[\\s*]*(@license\\b.*|The [a-z0-9-]+ License (\\([a-z0-9-]+\\))?\\s*)")
) > 1
}

View File

@@ -0,0 +1,93 @@
/**
* Provides classes for reasoning about cookies.
*/
import javascript
/**
* A model of the `js-cookie` library (https://github.com/js-cookie/js-cookie).
*/
private module JsCookie {
/**
* Gets a function call that invokes method `name` of the `js-cookie` library.
*/
DataFlow::CallNode libMemberCall(string name) {
result = DataFlow::globalVarRef("Cookie").getAMemberCall(name) or
result = DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict").getAMemberCall(name) or
result = DataFlow::moduleMember("js-cookie", name).getACall()
}
class ReadAccess extends PersistentReadAccess, DataFlow::CallNode {
ReadAccess() { this = libMemberCall("get") }
override PersistentWriteAccess getAWrite() {
getArgument(0).mayHaveStringValue(result.(WriteAccess).getKey())
}
}
class WriteAccess extends PersistentWriteAccess, DataFlow::CallNode {
WriteAccess() { this = libMemberCall("set") }
string getKey() { getArgument(0).mayHaveStringValue(result) }
override DataFlow::Node getValue() { result = getArgument(1) }
}
}
/**
* A model of the `browser-cookies` library (https://github.com/voltace/browser-cookies).
*/
private module BrowserCookies {
/**
* Gets a function call that invokes method `name` of the `browser-cookies` library.
*/
DataFlow::CallNode libMemberCall(string name) {
result = DataFlow::moduleMember("browser-cookies", name).getACall()
}
class ReadAccess extends PersistentReadAccess, DataFlow::CallNode {
ReadAccess() { this = libMemberCall("get") }
override PersistentWriteAccess getAWrite() {
getArgument(0).mayHaveStringValue(result.(WriteAccess).getKey())
}
}
class WriteAccess extends PersistentWriteAccess, DataFlow::CallNode {
WriteAccess() { this = libMemberCall("set") }
string getKey() { getArgument(0).mayHaveStringValue(result) }
override DataFlow::Node getValue() { result = getArgument(1) }
}
}
/**
* A model of the `cookie` library (https://github.com/jshttp/cookie).
*/
private module LibCookie {
/**
* Gets a function call that invokes method `name` of the `cookie` library.
*/
DataFlow::CallNode libMemberCall(string name) {
result = DataFlow::moduleMember("cookie", name).getACall()
}
class ReadAccess extends PersistentReadAccess {
string key;
ReadAccess() { this = libMemberCall("parse").getAPropertyRead(key) }
override PersistentWriteAccess getAWrite() {
key = result.(WriteAccess).getKey()
}
}
class WriteAccess extends PersistentWriteAccess, DataFlow::CallNode {
WriteAccess() { this = libMemberCall("serialize") }
string getKey() { getArgument(0).mayHaveStringValue(result) }
override DataFlow::Node getValue() { result = getArgument(1) }
}
}

View File

@@ -77,7 +77,7 @@ module CommandInjection {
override predicate isSource(DataFlow::Node nd) {
nd instanceof DataFlow::ArrayCreationNode
or
exists (StringLiteral shell | shellCmd(shell, _) |
exists (ConstantString shell | shellCmd(shell, _) |
nd = DataFlow::valueNode(shell)
)
}
@@ -96,14 +96,14 @@ module CommandInjection {
* That is, either `shell` is a Unix shell (`sh` or similar) and
* `arg` is `"-c"`, or `shell` is `cmd.exe` and `arg` is `"/c"`.
*/
private predicate shellCmd(StringLiteral shell, string arg) {
exists (string s | s = shell.getValue() |
private predicate shellCmd(ConstantString shell, string arg) {
exists (string s | s = shell.getStringValue() |
(s = "sh" or s = "bash" or s = "/bin/sh" or s = "/bin/bash")
and
arg = "-c"
)
or
exists (string s | s = shell.getValue().toLowerCase() |
exists (string s | s = shell.getStringValue().toLowerCase() |
(s = "cmd" or s = "cmd.exe")
and
(arg = "/c" or arg = "/C")
@@ -126,7 +126,7 @@ module CommandInjection {
*/
private predicate indirectCommandInjection(DataFlow::Node sink, SystemCommandExecution sys) {
exists (ArgumentListTracking cfg, DataFlow::ArrayCreationNode args,
StringLiteral shell, string dashC |
ConstantString shell, string dashC |
shellCmd(shell, dashC) and
cfg.hasFlow(DataFlow::valueNode(shell), sys.getACommandArgument()) and
cfg.hasFlow(args, sys.getArgumentList()) and

View File

@@ -167,6 +167,44 @@ class WebStorageWrite extends Expr {
}
}
/**
* Persistent storage through web storage such as `localStorage` or `sessionStorage`.
*/
private module PersistentWebStorage {
private DataFlow::SourceNode webStorage(string kind) {
(kind = "localStorage" or kind = "sessionStorage") and
result = DataFlow::globalVarRef(kind)
}
/**
* A read access.
*/
class ReadAccess extends PersistentReadAccess, DataFlow::CallNode {
string kind;
ReadAccess() { this = webStorage(kind).getAMethodCall("getItem") }
override PersistentWriteAccess getAWrite() {
getArgument(0).mayHaveStringValue(result.(WriteAccess).getKey()) and
result.(WriteAccess).getKind() = kind
}
}
/**
* A write access.
*/
class WriteAccess extends PersistentWriteAccess, DataFlow::CallNode {
string kind;
WriteAccess() { this = webStorage(kind).getAMethodCall("setItem") }
string getKey() { getArgument(0).mayHaveStringValue(result) }
string getKind() { result = kind }
override DataFlow::Node getValue() { result = getArgument(1) }
}
}
/**
* An event handler that handles `postMessage` events.
*/
@@ -199,4 +237,24 @@ private class PostMessageEventParameter extends RemoteFlowSource {
override string getSourceType() {
result = "postMessage event"
}
}
}
/**
* An access to `window.name`, which can be controlled by the opener of the window,
* even if the window is opened from a foreign domain.
*/
private class WindowNameAccess extends RemoteFlowSource {
WindowNameAccess() {
this = DataFlow::globalObjectRef().getAPropertyRead("name")
or
// Reference to `name` on a container that does not assign to it.
this.accessesGlobal("name") and
not exists(VarDef def |
def.getAVariable().(GlobalVariable).getName() = "name" and
def.getContainer() = this.asExpr().getContainer())
}
override string getSourceType() {
result = "Window name"
}
}

View File

@@ -68,7 +68,7 @@ module InsecureRandomness {
* A simple random number generator that is not cryptographically secure.
*/
class DefaultSource extends Source, DataFlow::ValueNode {
override CallExpr astNode;
override InvokeExpr astNode;
DefaultSource() {
exists(DataFlow::ModuleImportNode mod, string name | mod.getPath() = name |
@@ -98,6 +98,9 @@ module InsecureRandomness {
or
// (new require('chance')).<name>()
this = DataFlow::moduleImport("chance").getAnInstantiation().getAMemberInvocation(_)
or
// require('crypto').pseudoRandomBytes()
this = DataFlow::moduleMember("crypto", "pseudoRandomBytes").getAnInvocation()
}
}

View File

@@ -6,3 +6,5 @@
| tst.js:15:1:15:12 | randomSeed() |
| tst.js:18:1:18:14 | uniqueRandom() |
| tst.js:22:1:22:12 | chance.XYZ() |
| tst.js:25:1:25:29 | crypto. ... es(100) |
| tst.js:26:1:26:33 | new cry ... es(100) |

View File

@@ -20,3 +20,7 @@ uniqueRandom();
var Chance = require('chance'),
chance = new Chance();
chance.XYZ();
let crypto = require('crypto');
crypto.pseudoRandomBytes(100);
new crypto.pseudoRandomBytes(100);

View File

@@ -0,0 +1,4 @@
| persistence.js:3:5:3:33 | localSt ... prop1') |
| persistence.js:6:5:6:35 | session ... prop2') |
| persistence.js:10:5:10:33 | localSt ... prop4') |
| persistence.js:13:5:13:35 | session ... prop5') |

View File

@@ -0,0 +1,4 @@
import javascript
from PersistentReadAccess read
select read

View File

@@ -0,0 +1,2 @@
| persistence.js:3:5:3:33 | localSt ... prop1') | persistence.js:2:5:2:37 | localSt ... 1', v1) |
| persistence.js:6:5:6:35 | session ... prop2') | persistence.js:5:5:5:39 | session ... 2', v2) |

View File

@@ -0,0 +1,4 @@
import javascript
from PersistentReadAccess read
select read, read.getAWrite()

View File

@@ -0,0 +1,4 @@
| persistence.js:2:5:2:37 | localSt ... 1', v1) | persistence.js:2:35:2:36 | v1 |
| persistence.js:5:5:5:39 | session ... 2', v2) | persistence.js:5:37:5:38 | v2 |
| persistence.js:8:5:8:37 | localSt ... 3', v3) | persistence.js:8:35:8:36 | v3 |
| persistence.js:12:5:12:37 | localSt ... 5', v5) | persistence.js:12:35:12:36 | v5 |

View File

@@ -0,0 +1,4 @@
import javascript
from PersistentWriteAccess write
select write, write.getValue()

View File

@@ -0,0 +1,14 @@
(function(){
localStorage.setItem('prop1', v1);
localStorage.getItem('prop1');
sessionStorage.setItem('prop2', v2);
sessionStorage.getItem('prop2');
localStorage.setItem('prop3', v3);
localStorage.getItem('prop4');
localStorage.setItem('prop5', v5);
sessionStorage.getItem('prop5');
});

View File

@@ -0,0 +1,3 @@
| tst.js:7:2:7:21 | js_cookie.get('key') |
| tst.js:12:2:12:27 | browser ... ('key') |
| tst.js:18:2:18:22 | cookie. ... ['key'] |

View File

@@ -0,0 +1,4 @@
import javascript
from PersistentReadAccess read
select read

View File

@@ -0,0 +1,3 @@
| tst.js:7:2:7:21 | js_cookie.get('key') | tst.js:6:2:6:30 | js_cook ... value') |
| tst.js:12:2:12:27 | browser ... ('key') | tst.js:11:2:11:36 | browser ... value') |
| tst.js:18:2:18:22 | cookie. ... ['key'] | tst.js:17:2:17:33 | cookie. ... value') |

View File

@@ -0,0 +1,4 @@
import javascript
from PersistentReadAccess read
select read, read.getAWrite()

View File

@@ -0,0 +1,3 @@
| tst.js:6:2:6:30 | js_cook ... value') | tst.js:6:23:6:29 | 'value' |
| tst.js:11:2:11:36 | browser ... value') | tst.js:11:29:11:35 | 'value' |
| tst.js:17:2:17:33 | cookie. ... value') | tst.js:17:26:17:32 | 'value' |

View File

@@ -0,0 +1,4 @@
import javascript
from PersistentWriteAccess write
select write, write.getValue()

View File

@@ -0,0 +1,19 @@
const js_cookie = require('js-cookie'),
browser_cookies = require('browser-cookies'),
cookie = require('cookie');
(function() {
js_cookie.set('key', 'value');
js_cookie.get('key');
});
(function() {
browser_cookies.set('key', 'value');
browser_cookies.get('key');
});
(function() {
cookie.serialize('key', 'value');
cookie.parse()['key'];
});

View File

@@ -29,10 +29,15 @@ nodes
| child_process-test.js:44:30:44:33 | args |
| child_process-test.js:46:9:46:12 | "sh" |
| child_process-test.js:46:15:46:18 | args |
| child_process-test.js:49:14:49:16 | cmd |
| child_process-test.js:49:19:49:22 | args |
| child_process-test.js:50:12:50:14 | cmd |
| child_process-test.js:50:17:50:20 | args |
| child_process-test.js:48:9:48:17 | args |
| child_process-test.js:48:16:48:17 | [] |
| child_process-test.js:50:15:50:17 | cmd |
| child_process-test.js:51:17:51:32 | `/bin` + "/bash" |
| child_process-test.js:51:35:51:38 | args |
| child_process-test.js:55:14:55:16 | cmd |
| child_process-test.js:55:19:55:22 | args |
| child_process-test.js:56:12:56:14 | cmd |
| child_process-test.js:56:17:56:20 | args |
edges
| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:17:13:17:15 | cmd |
| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:18:17:18:19 | cmd |
@@ -44,6 +49,7 @@ edges
| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:25:21:25:23 | cmd |
| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:39:26:39:28 | cmd |
| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:43:15:43:17 | cmd |
| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:50:15:50:17 | cmd |
| child_process-test.js:6:15:6:38 | url.par ... , true) | child_process-test.js:6:15:6:44 | url.par ... ).query |
| child_process-test.js:6:15:6:44 | url.par ... ).query | child_process-test.js:6:15:6:49 | url.par ... ry.path |
| child_process-test.js:6:15:6:49 | url.par ... ry.path | child_process-test.js:6:9:6:49 | cmd |
@@ -58,10 +64,12 @@ edges
| child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args |
| child_process-test.js:41:9:41:17 | args | child_process-test.js:46:15:46:18 | args |
| child_process-test.js:41:16:41:17 | [] | child_process-test.js:41:9:41:17 | args |
| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:49:14:49:16 | cmd |
| child_process-test.js:46:15:46:18 | args | child_process-test.js:49:19:49:22 | args |
| child_process-test.js:49:14:49:16 | cmd | child_process-test.js:50:12:50:14 | cmd |
| child_process-test.js:49:19:49:22 | args | child_process-test.js:50:17:50:20 | args |
| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:55:14:55:16 | cmd |
| child_process-test.js:46:15:46:18 | args | child_process-test.js:55:19:55:22 | args |
| child_process-test.js:48:9:48:17 | args | child_process-test.js:51:35:51:38 | args |
| child_process-test.js:48:16:48:17 | [] | child_process-test.js:48:9:48:17 | args |
| child_process-test.js:55:14:55:16 | cmd | child_process-test.js:56:12:56:14 | cmd |
| child_process-test.js:55:19:55:22 | args | child_process-test.js:56:17:56:20 | args |
#select
| child_process-test.js:17:13:17:15 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:17:13:17:15 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| child_process-test.js:18:17:18:19 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:18:17:18:19 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
@@ -73,4 +81,5 @@ edges
| child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| child_process-test.js:39:5:39:31 | cp.spaw ... cmd ]) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:39:26:39:28 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| child_process-test.js:44:5:44:34 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| child_process-test.js:50:3:50:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| child_process-test.js:51:5:51:39 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:50:15:50:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| child_process-test.js:56:3:56:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |

View File

@@ -44,6 +44,12 @@ var server = http.createServer(function(req, res) {
cp.execFile("/bin/bash", args); // NOT OK
run("sh", args);
let args = [];
args[0] = `-` + "c";
args[1] = cmd;
cp.execFile(`/bin` + "/bash", args); // NOT OK
});
function run(cmd, args) {

View File

@@ -54,6 +54,12 @@ nodes
| react-native.js:7:17:7:33 | req.param("code") |
| react-native.js:8:18:8:24 | tainted |
| react-native.js:9:27:9:33 | tainted |
| stored-xss.js:2:39:2:55 | document.location |
| stored-xss.js:2:39:2:62 | documen ... .search |
| stored-xss.js:3:35:3:51 | document.location |
| stored-xss.js:3:35:3:58 | documen ... .search |
| stored-xss.js:5:20:5:52 | session ... ssion') |
| stored-xss.js:8:20:8:48 | localSt ... local') |
| string-manipulations.js:3:16:3:32 | document.location |
| string-manipulations.js:4:16:4:32 | document.location |
| string-manipulations.js:4:16:4:37 | documen ... on.href |
@@ -205,6 +211,9 @@ nodes
| tst.js:244:39:244:55 | props.propTainted |
| tst.js:248:60:248:82 | this.st ... Tainted |
| tst.js:252:23:252:29 | tainted |
| tst.js:256:7:256:17 | window.name |
| tst.js:257:7:257:10 | name |
| tst.js:261:11:261:21 | window.name |
| winjs.js:2:7:2:53 | tainted |
| winjs.js:2:17:2:33 | document.location |
| winjs.js:2:17:2:40 | documen ... .search |
@@ -268,6 +277,10 @@ edges
| react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted |
| react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted |
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
| stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search |
| stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') |
| stored-xss.js:3:35:3:51 | document.location | stored-xss.js:3:35:3:58 | documen ... .search |
| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') |
| string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href |
| string-manipulations.js:5:16:5:32 | document.location | string-manipulations.js:5:16:5:37 | documen ... on.href |
| string-manipulations.js:5:16:5:37 | documen ... on.href | string-manipulations.js:5:16:5:47 | documen ... lueOf() |

View File

@@ -17,6 +17,12 @@ nodes
| react-native.js:7:17:7:33 | req.param("code") |
| react-native.js:8:18:8:24 | tainted |
| react-native.js:9:27:9:33 | tainted |
| stored-xss.js:2:39:2:55 | document.location |
| stored-xss.js:2:39:2:62 | documen ... .search |
| stored-xss.js:3:35:3:51 | document.location |
| stored-xss.js:3:35:3:58 | documen ... .search |
| stored-xss.js:5:20:5:52 | session ... ssion') |
| stored-xss.js:8:20:8:48 | localSt ... local') |
| string-manipulations.js:3:16:3:32 | document.location |
| string-manipulations.js:4:16:4:32 | document.location |
| string-manipulations.js:4:16:4:37 | documen ... on.href |
@@ -162,6 +168,9 @@ nodes
| tst.js:244:39:244:55 | props.propTainted |
| tst.js:248:60:248:82 | this.st ... Tainted |
| tst.js:252:23:252:29 | tainted |
| tst.js:256:7:256:17 | window.name |
| tst.js:257:7:257:10 | name |
| tst.js:261:11:261:21 | window.name |
| winjs.js:2:7:2:53 | tainted |
| winjs.js:2:17:2:33 | document.location |
| winjs.js:2:17:2:40 | documen ... .search |
@@ -183,6 +192,10 @@ edges
| react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted |
| react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted |
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
| stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search |
| stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') |
| stored-xss.js:3:35:3:51 | document.location | stored-xss.js:3:35:3:58 | documen ... .search |
| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') |
| string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href |
| string-manipulations.js:5:16:5:32 | document.location | string-manipulations.js:5:16:5:37 | documen ... on.href |
| string-manipulations.js:5:16:5:37 | documen ... on.href | string-manipulations.js:5:16:5:47 | documen ... lueOf() |
@@ -307,6 +320,8 @@ edges
| nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | HTML injection vulnerability due to $@. | nodemailer.js:13:50:13:66 | req.query.message | user-provided value |
| react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
| react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
| stored-xss.js:5:20:5:52 | session ... ssion') | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:5:20:5:52 | session ... ssion') | Cross-site scripting vulnerability due to $@. | stored-xss.js:2:39:2:55 | document.location | user-provided value |
| stored-xss.js:8:20:8:48 | localSt ... local') | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:8:20:8:48 | localSt ... local') | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value |
| string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | Cross-site scripting vulnerability due to $@. | string-manipulations.js:3:16:3:32 | document.location | user-provided value |
| string-manipulations.js:4:16:4:37 | documen ... on.href | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | Cross-site scripting vulnerability due to $@. | string-manipulations.js:4:16:4:32 | document.location | user-provided value |
| string-manipulations.js:5:16:5:47 | documen ... lueOf() | string-manipulations.js:5:16:5:32 | document.location | string-manipulations.js:5:16:5:47 | documen ... lueOf() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:5:16:5:32 | document.location | user-provided value |
@@ -360,5 +375,8 @@ edges
| tst.js:224:28:224:46 | this.props.tainted3 | tst.js:194:19:194:35 | document.location | tst.js:224:28:224:46 | this.props.tainted3 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value |
| tst.js:228:32:228:49 | prevProps.tainted4 | tst.js:194:19:194:35 | document.location | tst.js:228:32:228:49 | prevProps.tainted4 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value |
| tst.js:248:60:248:82 | this.st ... Tainted | tst.js:194:19:194:35 | document.location | tst.js:248:60:248:82 | this.st ... Tainted | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value |
| tst.js:256:7:256:17 | window.name | tst.js:256:7:256:17 | window.name | tst.js:256:7:256:17 | window.name | Cross-site scripting vulnerability due to $@. | tst.js:256:7:256:17 | window.name | user-provided value |
| tst.js:257:7:257:10 | name | tst.js:257:7:257:10 | name | tst.js:257:7:257:10 | name | Cross-site scripting vulnerability due to $@. | tst.js:257:7:257:10 | name | user-provided value |
| tst.js:261:11:261:21 | window.name | tst.js:261:11:261:21 | window.name | tst.js:261:11:261:21 | window.name | Cross-site scripting vulnerability due to $@. | tst.js:261:11:261:21 | window.name | user-provided value |
| winjs.js:3:43:3:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:3:43:3:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value |
| winjs.js:4:43:4:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:4:43:4:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value |

View File

@@ -0,0 +1,9 @@
(function() {
sessionStorage.setItem('session', document.location.search);
localStorage.setItem('local', document.location.search);
$('myId').html(sessionStorage.getItem('session')); // NOT OK
$('myId').html(localStorage.getItem('session')); // OK
$('myId').html(sessionStorage.getItem('local')); // OK
$('myId').html(localStorage.getItem('local')); // NOT OK
});

View File

@@ -251,3 +251,14 @@ function react(){
(<C3 propTainted={tainted}/>);
}
function windowName() {
$(window.name); // NOT OK
$(name); // NOT OK
}
function windowNameAssigned() {
for (name of ['a', 'b']) {
$(window.name); // NOT OK
$(name); // OK
}
}

View File

@@ -9,3 +9,9 @@
| tst.js:37:20:37:23 | /"/g | This does not backslash-escape the backslash character. |
| tst.js:41:20:41:22 | "/" | This replaces only the first occurrence of "/". |
| tst.js:45:20:45:24 | "%25" | This replaces only the first occurrence of "%25". |
| tst.js:49:20:49:22 | `'` | This replaces only the first occurrence of `'`. |
| tst.js:53:20:53:22 | "'" | This replaces only the first occurrence of "'". |
| tst.js:57:20:57:22 | `'` | This replaces only the first occurrence of `'`. |
| tst.js:61:20:61:27 | "'" + "" | This replaces only the first occurrence of "'" + "". |
| tst.js:65:20:65:22 | "'" | This replaces only the first occurrence of "'". |
| tst.js:69:20:69:27 | "'" + "" | This replaces only the first occurrence of "'" + "". |

View File

@@ -45,6 +45,29 @@ function bad11(s) {
return s.replace("%25", "%"); // NOT OK
}
function bad12(s) {
return s.replace(`'`, ""); // NOT OK
}
function bad13(s) {
return s.replace("'", ``); // NOT OK
}
function bad14(s) {
return s.replace(`'`, ``); // NOT OK
}
function bad15(s) {
return s.replace("'" + "", ""); // NOT OK
}
function bad16(s) {
return s.replace("'", "" + ""); // NOT OK
}
function bad17(s) {
return s.replace("'" + "", "" + ""); // NOT OK
}
function good1(s) {
while (s.indexOf("'") > 0)
@@ -120,6 +143,12 @@ app.get('/some/path', function(req, res) {
bad9(untrusted);
bad10(untrusted);
bad11(untrusted);
bad12(untrusted);
bad13(untrusted);
bad14(untrusted);
bad15(untrusted);
bad16(untrusted);
bad17(untrusted);
good1(untrusted);
good2(untrusted);

View File

@@ -0,0 +1,5 @@
/*
* Code generated by Microsoft (R) AutoRest Code Generator.
* Changes may cause incorrect behavior and will be lost if the code is
* regenerated.
*/

View File

@@ -1,7 +1,10 @@
| AutoRest.js:0:0:0:0 | AutoRest.js | generated |
| ai.1.2.3-build0123.js:0:0:0:0 | ai.1.2.3-build0123.js | library |
| bundle-directive.js:0:0:0:0 | bundle-directive.js | generated |
| data.js:0:0:0:0 | data.js | generated |
| etherpad.html:0:0:0:0 | etherpad.html | generated |
| exported-data.js:0:0:0:0 | exported-data.js | generated |
| htmltidy.html:0:0:0:0 | htmltidy.html | generated |
| jison-lex.js:0:0:0:0 | jison-lex.js | generated |
| jison.js:0:0:0:0 | jison.js | generated |
| jquery-datatables.js:0:0:0:0 | jquery-datatables.js | library |
@@ -12,12 +15,19 @@
| multi-part-bundle.html:0:0:0:0 | multi-part-bundle.html | generated |
| multi-part-bundle.js:0:0:0:0 | multi-part-bundle.js | generated |
| multiple-licenses-2.js:0:0:0:0 | multiple-licenses-2.js | generated |
| multiple-licenses-3.js:0:0:0:0 | multiple-licenses-3.js | generated |
| multiple-licenses-4.js:0:0:0:0 | multiple-licenses-4.js | generated |
| multiple-licenses.js:0:0:0:0 | multiple-licenses.js | generated |
| opal-test.js:0:0:0:0 | opal-test.js | generated |
| orgmode.html:0:0:0:0 | orgmode.html | generated |
| pandoc.html:0:0:0:0 | pandoc.html | generated |
| peg-js.js:0:0:0:0 | peg-js.js | generated |
| polymer.html:0:0:0:0 | polymer.html | template |
| purs-bundle.js:0:0:0:0 | purs-bundle.js | generated |
| purs.js:0:0:0:0 | purs.js | generated |
| some-template.html:0:0:0:0 | some-template.html | template |
| templ.js:0:0:0:0 | templ.js | template |
| textmate.html:0:0:0:0 | textmate.html | generated |
| tmpl2.html:0:0:0:0 | tmpl2.html | template |
| tmpl.html:0:0:0:0 | tmpl.html | template |
| tst.browserify.js:0:0:0:0 | tst.browserify.js | generated |

View File

@@ -1,7 +1,10 @@
| AutoRest.js:1:1:5:3 | /*\\n * C ... ed.\\n */ | Microsoft (R) AutoRest Code Generator |
| jison-lex.js:1:1:1:34 | /* gene ... .2.1 */ | jison-lex |
| jison.js:1:1:1:38 | /* pars ... 4.13 */ | jison |
| jsx-old.js:1:1:1:106 | // gene ... 977102) | JSX |
| jsx.js:1:1:1:105 | // gene ... 977102) | JSX |
| opal-test.js:1:1:1:30 | /* Gene ... 10.3 */ | Opal |
| peg-js.js:2:3:6:5 | /*\\n * ... /\\n */ | PEG.js |
| purs-bundle.js:1:1:1:34 | // Gene ... 0.11.7 | purs |
| purs.js:1:1:1:35 | // Gene ... 0.11.7 | purs |
| tst.dart.js:1:1:1:57 | // Gene ... mpiler. | dart2js |

View File

@@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<title><%- padId %></title>
<meta name="generator" content="Etherpad">
<script type="text/javascript">//</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,9 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy for Linux/x86 (vers 25 March 2009), see www.w3.org">
<script type="text/javascript">//</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,6 @@
/**
* @license
*/
/**
* @license
*/

View File

@@ -0,0 +1,6 @@
/**
* The MIT License (MIT)
*/
/**
* The MIT License (MIT)
*/

View File

@@ -0,0 +1,9 @@
/**
* The MIT License (MIT)
*/
/**
* The user needs to accept the licence.
*/
function hasAcceptedLicense(){
// ...
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta name="generator" content="Org-mode"/>
<script type="text/javascript">//</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
<meta name="generator" content="pandoc" />
<script type="text/javascript">//</script>
</head>
<body>
</html>

View File

@@ -0,0 +1 @@
// Generated by purs bundle 0.11.7

View File

@@ -0,0 +1 @@
// Generated by purs version 0.11.7

View File

@@ -0,0 +1,9 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta name="generator" content="TextMate http://macromates.com/">
<script type="text/javascript">//</script>
</head>
<body>
</html>