Merge pull request #73 from esben-semmle/js/cleartext-logging-query

Approved by xiemaisi
This commit is contained in:
semmle-qlci
2018-08-22 08:04:36 +01:00
committed by GitHub
26 changed files with 663 additions and 26 deletions

View File

@@ -85,6 +85,7 @@
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
| Clear-text logging of sensitive information (`js/clear-text-logging`) | security, external/cwe/cwe-312, external/cwe/cwe-315, external/cwe/cwe-359 | Highlights logging of sensitive information, indicating a violation of [CWE-312](https://cwe.mitre.org/data/definitions/312.html). Results shown on LGTM by default. |
| Disabling Electron webSecurity (`js/disabling-electron-websecurity`) | security, frameworks/electron | Highlights Electron browser objects that are created with the `webSecurity` property set to false. Results shown on LGTM by default. |
| Enabling Electron allowRunningInsecureContent (`js/enabling-electron-insecure-content`) | security, frameworks/electron | Highlights Electron browser objects that are created with the `allowRunningInsecureContent` property set to true. Results shown on LGTM by default. |
| Use of externally-controlled format string (`js/tainted-format-string`) | security, external/cwe/cwe-134 | Highlights format strings containing user-provided data, indicating a violation of [CWE-134](https://cwe.mitre.org/data/definitions/134.html). Results shown on LGTM by default. |

View File

@@ -9,6 +9,7 @@
+ semmlecode-javascript-queries/Security/CWE-134/TaintedFormatString.ql: /Security/CWE/CWE-134
+ semmlecode-javascript-queries/Security/CWE-209/StackTraceExposure.ql: /Security/CWE/CWE-209
+ semmlecode-javascript-queries/Security/CWE-312/CleartextStorage.ql: /Security/CWE/CWE-312
+ semmlecode-javascript-queries/Security/CWE-312/CleartextLogging.ql: /Security/CWE/CWE-312
+ semmlecode-javascript-queries/Security/CWE-313/PasswordInConfigurationFile.ql: /Security/CWE/CWE-313
+ semmlecode-javascript-queries/Security/CWE-327/BrokenCryptoAlgorithm.ql: /Security/CWE/CWE-327
+ semmlecode-javascript-queries/Security/CWE-338/InsecureRandomness.ql: /Security/CWE/CWE-338

View File

@@ -0,0 +1,5 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="CleartextStorage.qhelp" /></qhelp>

View File

@@ -0,0 +1,38 @@
/**
* @name Clear-text logging of sensitive information
* @description Logging sensitive information without encryption or hashing can
* expose it to an attacker.
* @kind problem
* @problem.severity error
* @precision high
* @id js/clear-text-logging
* @tags security
* external/cwe/cwe-312
* external/cwe/cwe-315
* external/cwe/cwe-359
*/
import javascript
import semmle.javascript.security.dataflow.CleartextLogging::CleartextLogging
/**
* Holds if `tl` is used in a browser environment.
*/
predicate inBrowserEnvironment(TopLevel tl) {
tl instanceof InlineScript or
tl instanceof CodeInAttribute or
exists (GlobalVarAccess e |
e.getTopLevel() = tl |
e.getName() = "window"
) or
exists (Module m | inBrowserEnvironment(m) |
tl = m.getAnImportedModule() or
m = tl.(Module).getAnImportedModule()
)
}
from Configuration cfg, Source source, DataFlow::Node sink
where cfg.hasFlow(source, sink) and
// ignore logging to the browser console (even though it is not a good practice)
not inBrowserEnvironment(sink.asExpr().getTopLevel())
select sink, "Sensitive data returned by $@ is logged here.", source, source.describe()

View File

@@ -15,13 +15,22 @@ which are stored on the machine of the end-user.
<p>
Ensure 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 lookup the
Instead, prefer storing, in the cookie, a key that can be used to look up the
sensitive information.
</p>
<p>
In general, decrypt sensitive information only at the point where it is
necessary for it to be used in cleartext.
</p>
<p>
Be aware that external processes often store the <code>standard
out</code> and <code>standard error</code> streams of the application,
causing logged sensitive information to be stored as well.
</p>
</recommendation>
<example>

View File

@@ -59,6 +59,7 @@ import semmle.javascript.frameworks.DigitalOcean
import semmle.javascript.frameworks.Electron
import semmle.javascript.frameworks.jQuery
import semmle.javascript.frameworks.LodashUnderscore
import semmle.javascript.frameworks.Logging
import semmle.javascript.frameworks.HttpFrameworks
import semmle.javascript.frameworks.NoSQL
import semmle.javascript.frameworks.PkgCloud

View File

@@ -316,13 +316,12 @@ module TaintTracking {
}
/**
* A taint propagating data flow edge arising from string append and other string
* operations defined in the standard library.
* A taint propagating data flow edge arising from string concatenations.
*
* Note that since we cannot easily distinguish string append from addition, we consider
* any `+` operation to propagate taint.
* Note that since we cannot easily distinguish string append from addition,
* we consider any `+` operation to propagate taint.
*/
private class StringManipulationTaintStep extends AdditionalTaintStep, DataFlow::ValueNode {
class StringConcatenationTaintStep extends AdditionalTaintStep, DataFlow::ValueNode {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
succ = this and
(
@@ -336,8 +335,19 @@ module TaintTracking {
or
// templating propagates taint
astNode.(TemplateLiteral).getAnElement() = pred.asExpr()
or
// other string operations that propagate taint
)
}
}
/**
* A taint propagating data flow edge arising from string manipulation
* functions defined in the standard library.
*/
private class StringManipulationTaintStep extends AdditionalTaintStep, DataFlow::ValueNode {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
succ = this and
(
// string operations that propagate taint
exists (string name | name = astNode.(MethodCallExpr).getMethodName() |
pred.asExpr() = astNode.(MethodCallExpr).getReceiver() and
( // sorted, interesting, properties of String.prototype

View File

@@ -0,0 +1,139 @@
/**
* Provides classes for working with logging libraries.
*/
import javascript
/**
* A call to a logging mechanism.
*/
abstract class LoggerCall extends DataFlow::CallNode {
/**
* Gets a node that contributes to the logged message.
*/
abstract DataFlow::Node getAMessageComponent();
}
/**
* Gets a log level name that is used in RFC5424, `npm`, `console`.
*/
private string getAStandardLoggerMethodName() {
result = "crit" or
result = "debug" or
result = "error" or
result = "emerg" or
result = "fatal" or
result = "info" or
result = "log" or
result = "notice" or
result = "silly" or
result = "trace" or
result = "warn"
}
/**
* Provides classes for working the builtin Node.js/Browser `console`.
*/
private module Console {
/**
* Gets a data flow source node for the console library.
*/
private DataFlow::SourceNode console() {
result = DataFlow::moduleImport("console") or
result = DataFlow::globalVarRef("console")
}
/**
* A call to the console logging mechanism.
*/
class ConsoleLoggerCall extends LoggerCall {
string name;
ConsoleLoggerCall() {
(
name = getAStandardLoggerMethodName() or
name = "assert"
) and
this = console().getAMethodCall(name)
}
override DataFlow::Node getAMessageComponent() {
if name = "assert" then
result = getArgument([1..getNumArgument()])
else
result = getAnArgument()
}
}
}
/**
* Provides classes for working with [loglevel](https://github.com/pimterry/loglevel).
*/
private module Loglevel {
/**
* A call to the loglevel logging mechanism.
*/
class LoglevelLoggerCall extends LoggerCall {
LoglevelLoggerCall() {
this = DataFlow::moduleMember("loglevel", getAStandardLoggerMethodName()).getACall()
}
override DataFlow::Node getAMessageComponent() {
result = getAnArgument()
}
}
}
/**
* Provides classes for working with [winston](https://github.com/winstonjs/winston).
*/
private module Winston {
/**
* A call to the winston logging mechanism.
*/
class WinstonLoggerCall extends LoggerCall, DataFlow::MethodCallNode {
WinstonLoggerCall() {
this = DataFlow::moduleMember("winston", "createLogger").getACall().getAMethodCall(getAStandardLoggerMethodName())
}
override DataFlow::Node getAMessageComponent() {
if getMethodName() = "log" then
result = getOptionArgument(0, "message")
else
result = getAnArgument()
}
}
}
/**
* Provides classes for working with [log4js](https://github.com/log4js-node/log4js-node).
*/
private module log4js {
/**
* A call to the log4js logging mechanism.
*/
class Log4jsLoggerCall extends LoggerCall {
Log4jsLoggerCall() {
this = DataFlow::moduleMember("log4js", "getLogger").getACall().getAMethodCall(getAStandardLoggerMethodName())
}
override DataFlow::Node getAMessageComponent() {
result = getAnArgument()
}
}
}

View File

@@ -11,27 +11,38 @@
import javascript
/** A regular expression that identifies strings that look like they represent secret data that are not passwords. */
private string suspiciousNonPassword() {
result = "(?is).*(secret|account|accnt|(?<!un)trusted).*"
}
/** A regular expression that identifies strings that look like they represent secret data that are passwords. */
private string suspiciousPassword() {
result = "(?is).*(password|passwd).*"
}
/** A regular expression that identifies strings that look like they represent secret data. */
private string suspicious() {
result = suspiciousPassword() or result = suspiciousNonPassword()
}
/**
* A string for `match` that identifies strings that look like they represent secret data that is
* hashed or encrypted.
* Provides heuristics for identifying names related to sensitive information.
*
* INTERNAL: Do not use directly.
*/
private string nonSuspicious() {
result = "(?is).*(hash|(?<!un)encrypted|\\bcrypt\\b).*"
module HeuristicNames {
/** A regular expression that identifies strings that look like they represent secret data that are not passwords. */
string suspiciousNonPassword() {
result = "(?is).*(secret|account|accnt|(?<!un)trusted).*"
}
/** A regular expression that identifies strings that look like they represent secret data that are passwords. */
string suspiciousPassword() {
result = "(?is).*(password|passwd).*"
}
/** A regular expression that identifies strings that look like they represent secret data. */
string suspicious() {
result = suspiciousPassword() or result = suspiciousNonPassword()
}
/**
* A regular expression that identifies strings that look like they represent data that is
* hashed or encrypted.
*/
string nonSuspicious() {
result = "(?is).*(redact|censor|obfuscate|hash|md5|sha|((?<!un)(en))?(crypt|code)).*"
}
}
private import HeuristicNames
/** An expression that might contain sensitive data. */
abstract class SensitiveExpr extends Expr {

View File

@@ -0,0 +1,202 @@
/**
* Provides a dataflow tracking configuration for reasoning about clear-text logging of sensitive information.
*/
import javascript
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.security.SensitiveActions::HeuristicNames
module CleartextLogging {
/**
* A data flow source for clear-text logging of sensitive information.
*/
abstract class Source extends DataFlow::Node {
/** Gets a string that describes the type of this data flow source. */
abstract string describe();
}
/**
* A data flow sink for clear-text logging of sensitive information.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A barrier for clear-text logging of sensitive information.
*/
abstract class Barrier extends DataFlow::Node { }
/**
* A dataflow tracking configuration for clear-text logging of sensitive information.
*
* This configuration identifies flows from `Source`s, which are sources of
* sensitive data, to `Sink`s, which is an abstract class representing all
* the places sensitive data may be stored in clear-text. Additional sources or sinks can be
* added either by extending the relevant class, or by subclassing this configuration itself,
* and amending the sources and sinks.
*/
class Configuration extends DataFlow::Configuration {
Configuration() { this = "CleartextLogging" }
override
predicate isSource(DataFlow::Node source) {
source instanceof Source
}
override
predicate isSink(DataFlow::Node sink) {
sink instanceof Sink
}
override
predicate isBarrier(DataFlow::Node node) {
node instanceof Barrier
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) {
any (TaintTracking::StringConcatenationTaintStep s).step(src, trg)
or
exists (string name | name = "toString" or name = "valueOf" |
src.(DataFlow::SourceNode).getAMethodCall(name) = trg
)
or
// A taint propagating data flow edge through objects: a tainted write taints the entire object.
exists (DataFlow::PropWrite write |
write.getRhs() = src and
trg.(DataFlow::SourceNode).flowsTo(write.getBase())
)
}
}
/**
* An argument to a logging mechanism.
*/
class LoggerSink extends Sink {
LoggerSink() {
this = any(LoggerCall log).getAMessageComponent()
}
}
/**
* A data flow node that does not contain a clear-text password, according to its syntactic name.
*/
private class NameGuidedNonCleartextPassword extends NonCleartextPassword {
NameGuidedNonCleartextPassword() {
exists (string name |
name.regexpMatch(nonSuspicious()) |
this.asExpr().(VarAccess).getName() = name
or
this.(DataFlow::PropRead).getPropertyName() = name
or
this.(DataFlow::InvokeNode).getCalleeName() = name
)
or
// avoid i18n strings
this.(DataFlow::PropRead).getBase().asExpr().(VarRef).getName().regexpMatch("(?is).*(messages|strings).*")
}
}
/**
* A data flow node that is definitely not an object.
*/
private class NonObject extends NonCleartextPassword {
NonObject() {
forall (AbstractValue v | v = analyze().getAValue() |
not v.getType() = TTObject()
)
}
}
/**
* A data flow node that receives flow that is not a clear-text password.
*/
private class NonCleartextPasswordFlow extends NonCleartextPassword {
NonCleartextPasswordFlow() {
any(NonCleartextPassword other).(DataFlow::SourceNode).flowsTo(this)
}
}
/**
* A call that might obfuscate a password, for example through hashing.
*/
private class ObfuscatorCall extends Barrier, DataFlow::InvokeNode {
ObfuscatorCall() {
getCalleeName().regexpMatch(nonSuspicious())
}
}
/**
* A data flow node that does not contain a clear-text password.
*/
private abstract class NonCleartextPassword extends DataFlow::Node { }
/**
* An object with a property that may contain password information
*
* This is a source since `console.log(obj)` will show the properties of `obj`.
*/
private class ObjectPasswordPropertySource extends DataFlow::ValueNode, Source {
string name;
ObjectPasswordPropertySource() {
exists (DataFlow::PropWrite write |
name.regexpMatch(suspiciousPassword()) and
not name.regexpMatch(nonSuspicious()) and
write = this.(DataFlow::SourceNode).getAPropertyWrite(name) and
// avoid safe values assigned to presumably unsafe names
not write.getRhs() instanceof NonCleartextPassword
)
}
override string describe() {
result = "an access to " + name
}
}
/** An access to a variable or property that might contain a password. */
private class ReadPasswordSource extends DataFlow::ValueNode, Source {
string name;
ReadPasswordSource() {
// avoid safe values assigned to presumably unsafe names
not this instanceof NonCleartextPassword and
name.regexpMatch(suspiciousPassword()) and
(
this.asExpr().(VarAccess).getName() = name
or
exists (DataFlow::SourceNode base |
this = base.getAPropertyRead(name) and
// avoid safe values assigned to presumably unsafe names
exists (DataFlow::SourceNode baseObj | baseObj.flowsTo(base) |
not base.getAPropertyWrite(name).getRhs() instanceof NonCleartextPassword
)
)
)
}
override string describe() {
result = "an access to " + name
}
}
/** A call that might return a password. */
private class CallPasswordSource extends DataFlow::ValueNode, DataFlow::InvokeNode, Source {
string name;
CallPasswordSource() {
name = getCalleeName() and
name.regexpMatch("(?is)getPassword")
}
override string describe() {
result = "a call to " + name
}
}
}

View File

@@ -0,0 +1,17 @@
| tst.js:3:1:3:26 | console ... ", arg) | tst.js:3:13:3:20 | "msg %s" |
| tst.js:3:1:3:26 | console ... ", arg) | tst.js:3:23:3:25 | arg |
| tst.js:4:1:4:28 | console ... ", arg) | tst.js:4:15:4:22 | "msg %s" |
| tst.js:4:1:4:28 | console ... ", arg) | tst.js:4:25:4:27 | arg |
| tst.js:5:1:5:28 | console ... ", arg) | tst.js:5:15:5:22 | "msg %s" |
| tst.js:5:1:5:28 | console ... ", arg) | tst.js:5:25:5:27 | arg |
| tst.js:7:1:7:34 | require ... ", arg) | tst.js:7:21:7:28 | "msg %s" |
| tst.js:7:1:7:34 | require ... ", arg) | tst.js:7:31:7:33 | arg |
| tst.js:9:1:9:38 | require ... ", arg) | tst.js:9:25:9:32 | "msg %s" |
| tst.js:9:1:9:38 | require ... ", arg) | tst.js:9:35:9:37 | arg |
| tst.js:11:1:11:73 | require ... other) | tst.js:11:50:11:63 | "msg with arg" |
| tst.js:12:1:12:53 | require ... ", arg) | tst.js:12:40:12:47 | "msg %s" |
| tst.js:12:1:12:53 | require ... ", arg) | tst.js:12:50:12:52 | arg |
| tst.js:14:1:14:48 | require ... ", arg) | tst.js:14:35:14:42 | "msg %s" |
| tst.js:14:1:14:48 | require ... ", arg) | tst.js:14:45:14:47 | arg |
| tst.js:16:1:16:35 | console ... ", arg) | tst.js:16:22:16:29 | "msg %s" |
| tst.js:16:1:16:35 | console ... ", arg) | tst.js:16:32:16:34 | arg |

View File

@@ -0,0 +1,4 @@
import javascript
from LoggerCall log
select log, log.getAMessageComponent()

View File

@@ -0,0 +1,16 @@
var requiredConsole = require("console");
console.log("msg %s", arg);
console.fatal("msg %s", arg);
console.debug("msg %s", arg);
requiredConsole.log("msg %s", arg);
require("loglevel").log("msg %s", arg);
require("winston").createLogger().log({ message: "msg with arg" }, other);
require("winston").createLogger().info("msg %s", arg);
require("log4js").getLogger().log("msg %s", arg);
console.assert(true, "msg %s", arg);

View File

@@ -0,0 +1,26 @@
| passwords.js:2:17:2:24 | password | Sensitive data returned by $@ is logged here. | passwords.js:2:17:2:24 | password | an access to password |
| passwords.js:3:17:3:26 | o.password | Sensitive data returned by $@ is logged here. | passwords.js:3:17:3:26 | o.password | an access to password |
| passwords.js:4:17:4:29 | getPassword() | Sensitive data returned by $@ is logged here. | passwords.js:4:17:4:29 | getPassword() | a call to getPassword |
| passwords.js:5:17:5:31 | o.getPassword() | Sensitive data returned by $@ is logged here. | passwords.js:5:17:5:31 | o.getPassword() | a call to getPassword |
| passwords.js:8:21:8:21 | x | Sensitive data returned by $@ is logged here. | passwords.js:10:11:10:18 | password | an access to password |
| passwords.js:12:18:12:25 | password | Sensitive data returned by $@ is logged here. | passwords.js:12:18:12:25 | password | an access to password |
| passwords.js:14:17:14:38 | name + ... assword | Sensitive data returned by $@ is logged here. | passwords.js:14:31:14:38 | password | an access to password |
| passwords.js:16:17:16:38 | `${name ... sword}` | Sensitive data returned by $@ is logged here. | passwords.js:16:29:16:36 | password | an access to password |
| passwords.js:21:17:21:20 | obj1 | Sensitive data returned by $@ is logged here. | passwords.js:18:16:20:5 | {\\n ... x\\n } | an access to password |
| passwords.js:26:17:26:20 | obj2 | Sensitive data returned by $@ is logged here. | passwords.js:24:12:24:19 | password | an access to password |
| passwords.js:29:17:29:20 | obj3 | Sensitive data returned by $@ is logged here. | passwords.js:30:14:30:21 | password | an access to password |
| passwords.js:78:17:78:38 | temp.en ... assword | Sensitive data returned by $@ is logged here. | passwords.js:77:37:77:53 | req.body.password | an access to password |
| passwords.js:81:17:81:31 | `pw: ${secret}` | Sensitive data returned by $@ is logged here. | passwords.js:80:18:80:25 | password | an access to password |
| passwords.js:93:21:93:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:93:39:93:46 | password | an access to password |
| passwords.js:98:21:98:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:98:39:98:46 | password | an access to password |
| passwords.js:105:21:105:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:105:39:105:46 | password | an access to password |
| passwords.js:110:21:110:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:110:39:110:46 | password | an access to password |
| passwords.js:114:25:114:50 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:114:43:114:50 | password | an access to password |
| passwords.js:119:21:119:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:119:39:119:46 | password | an access to password |
| passwords.js:122:17:122:49 | name + ... tring() | Sensitive data returned by $@ is logged here. | passwords.js:122:31:122:38 | password | an access to password |
| passwords.js:123:17:123:48 | name + ... lueOf() | Sensitive data returned by $@ is logged here. | passwords.js:123:31:123:38 | password | an access to password |
| passwords_in_server_1.js:6:13:6:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_1.js:6:13:6:20 | password | an access to password |
| passwords_in_server_2.js:3:13:3:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_2.js:3:13:3:20 | password | an access to password |
| passwords_in_server_3.js:2:13:2:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_3.js:2:13:2:20 | password | an access to password |
| passwords_in_server_4.js:2:13:2:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_4.js:2:13:2:20 | password | an access to password |
| passwords_in_server_5.js:8:17:8:17 | x | Sensitive data returned by $@ is logged here. | passwords_in_server_5.js:4:7:4:24 | req.query.password | an access to password |

View File

@@ -0,0 +1 @@
Security/CWE-312/CleartextLogging.ql

View File

@@ -0,0 +1,2 @@
import foo from "foo";
window.location;

View File

@@ -0,0 +1,124 @@
(function() {
console.log(password); // NOT OK
console.log(o.password); // NOT OK
console.log(getPassword()); // NOT OK
console.log(o.getPassword()); // NOT OK
function myLog(x) {
console.log(x); // NOT OK
}
myLog(password);
console.info(password); // NOT OK
console.log(name + ", " + password); // NOT OK
console.log(`${name}, ${password}`); // NOT OK
var obj1 = {
password: x
};
console.log(obj1); // NOT OK
var obj2 = {
x: password
};
console.log(obj2); // NOT OK
var obj3 = {};
console.log(obj3);
obj3.x = password; // NOT OK
var fixed_password = "123";
console.log(fixed_password); // OK
console.log(messages.IncorrectPasswordError); // OK
console.log(this.hashed_password); // OK
console.log(login.wrappedJSObject.encryptedPassword); // OK
console.log(HTML5QQ.encodedPassword); // OK
console.log({password: crypt(pw)}); // OK
var actually_secure_password = crypt(password); // OK
console.log(actually_secure_password); // OK
var user1 = {};
user1.crypted_password = x();
console.log(user1); // OK
var user2 = {};
user2.password = hash();
console.log(user2); // OK
var user3 = {
password: encryptLib.encryptPassword(req.body.password)
};
console.log(user3); // OK
var actually_ok_password_1 = hashed1();
console.log(actually_ok_password_1);
var hashed2 = actually_ok_password_2();
console.log(hashed2); // OK
console.log(this._passwordMD5); // OK
console.log(this._password_sha); // OK
var utilityObject = {
passwordSet: function(){}
}
console.log(utilityObject); // OK
var displayedPassword = password? null: "(hidden)";
var config = {
password: displayedPassword
};
console.log(config); // OK
var temp = { encryptedPassword: req.body.password };
console.log(temp.encryptedPassword); // OK XXX
var secret = password;
console.log(`pw: ${secret}`); // NOT OK
function redact(kind, value) {
if (value && kind == 'password') {
return "********"
}
return value;
}
console.log("Password is: " + redact('password', password));
if (environment.isTestEnv()) {
console.log("Password is: " + password); // OK, but still flagged
}
if (environment.is(TEST)) {
// NB: for security reasons, we only log passwords in test environments
console.log("Password is: " + password); // OK, but still flagged
}
if (x.test(y)) {
f();
// ...
console.log("Password is: " + password); // NOT OK
// ...
}
if (environment.isTestEnv())
console.log("Password is: " + password); // OK, but still flagged
if (x.test(y)) {
if (f()) {
console.log("Password is: " + password); // NOT OK
}
}
if (!environment.isProduction()) {
console.log("Password is: " + password); // OK, but still flagged
}
console.log(name + ", " + password.toString()); // NOT OK
console.log(name + ", " + password.valueOf()); // NOT OK
});

View File

@@ -0,0 +1,2 @@
window.location;
console.log(password);

View File

@@ -0,0 +1,2 @@
import browser from "./browser";
console.log(password);

View File

@@ -0,0 +1,6 @@
var express = require('express');
var app = express();
app.get('/some/path', function() {
})
console.log(password);

View File

@@ -0,0 +1,3 @@
require("foo");
(function (req, res){});
console.log(password);

View File

@@ -0,0 +1,2 @@
var server = require("./server");
console.log(password);

View File

@@ -0,0 +1,2 @@
require("foo");
console.log(password);

View File

@@ -0,0 +1,9 @@
var express = require('express');
var app = express();
app.get('/some/path', function() {
f(req.query.password);
})
function f(x) {
console.log(x);
}

View File

@@ -0,0 +1,2 @@
require("foo");
(function (req, res){})

View File

@@ -0,0 +1,2 @@
require("./server.js")
require("./passwords_in_server_4.js")