diff --git a/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qhelp b/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qhelp new file mode 100644 index 000000000000..8d7d7e73a88b --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qhelp @@ -0,0 +1,35 @@ + + + +

An original client IP address is retrieved from an http header (X-Forwarded-For or X-Real-IP or Proxy-Client-IP +etc.), which is used to ensure security. Attackers can forge the value of these identifiers to +bypass a blacklist, for example.

+ +
+ + +

Do not trust the values of HTTP headers allegedly identifying the originating IP. If you are aware your application will run behind some reverse proxies then the last entry of a X-Forwarded-For header value may be more trustworthy than the rest of it because some reverse proxies append the IP address they observed to the end of any remote-supplied header.

+ +
+ + +

The following examples show the bad case and the good case respectively. +In /bad1 endpoint, the client IP from the X-Forwarded-For header is used directly to check against a whitelist. In /bad2 endpoint, this value is split into multiple IPs, separated by a comma, but the less-trustworthy first one is used. Both of these examples could be deceived by providing a forged HTTP header. +The endpoint /good similarly splits the value from X-Forwarded-For header but uses the last, more trustworthy entry.

+ + + +
+ + +
  • Dennis Schneider: +Prevent IP address spoofing with X-Forwarded-For header when using AWS ELB and Clojure Ring +
  • + +
  • Security Rule Zero: A Warning about X-Forwarded-For +
  • + +
    +
    \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql b/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql new file mode 100644 index 000000000000..5aacf8f6cf9b --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql @@ -0,0 +1,56 @@ +/** + * @name IP address spoofing + * @description A remote endpoint identifier is read from an HTTP header. Attackers can modify the value + * of the identifier to forge the client ip. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/ip-address-spoofing + * @tags security + * external/cwe/cwe-348 + */ + +import javascript +import semmle.javascript.dataflow.DataFlow +import semmle.javascript.dataflow.TaintTracking +import ClientSuppliedIpUsedInSecurityCheckLib + +/** + * Taint-tracking configuration tracing flow from obtaining a client ip from an HTTP header to a sensitive use. + */ +class ClientSuppliedIpUsedInSecurityCheckConfig extends TaintTracking::Configuration { + ClientSuppliedIpUsedInSecurityCheckConfig() { this = "ClientSuppliedIpUsedInSecurityCheckConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof ClientSuppliedIp } + + override predicate isSink(DataFlow::Node sink) { sink instanceof PossibleSecurityCheck } + + /** + * Splitting a header value by `,` and taking an entry other than the first is sanitizing, because + * later entries may originate from more-trustworthy intermediate proxies, not the original client. + */ + override predicate isSanitizer(DataFlow::Node node) { + // ip.split(",").pop(); or var temp = ip.split(","); ip = temp.pop(); + exists(DataFlow::MethodCallNode split, DataFlow::MethodCallNode pop | + split = node and + split.getMethodName() = "split" and + pop.getMethodName() = "pop" and + split.getACall() = pop + ) + or + // ip.split(",")[ip.split(",").length - 1]; or var temp = ip.split(","); ip = temp[temp.length - 1]; + exists(DataFlow::MethodCallNode split, DataFlow::PropRead read | + split = node and + split.getMethodName() = "split" and + read = split.getAPropertyRead() and + not read.getPropertyNameExpr().getIntValue() = 0 + ) + } +} + +from + ClientSuppliedIpUsedInSecurityCheckConfig config, DataFlow::PathNode source, + DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "IP address spoofing might include code from $@.", + source.getNode(), "this user input" diff --git a/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheckLib.qll b/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheckLib.qll new file mode 100644 index 000000000000..2f59ef9e01bd --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheckLib.qll @@ -0,0 +1,78 @@ +private import javascript +private import DataFlow::PathGraph +private import semmle.javascript.dataflow.DataFlow + +/** + * A data flow source of the client ip obtained according to the remote endpoint identifier specified + * (`X-Forwarded-For`, `X-Real-IP`, `Proxy-Client-IP`, etc.) in the header. + * + * For example: `req.headers["X-Forwarded-For"]`. + */ +abstract class ClientSuppliedIp extends DataFlow::Node { } + +private class GenericClientSuppliedIp extends ClientSuppliedIp { + GenericClientSuppliedIp() { + exists(DataFlow::SourceNode source, DataFlow::PropRead read | + this.(RemoteFlowSource).getSourceType() = "Server request header" and source = this + | + read.getPropertyName().toLowerCase() = clientIpParameterName() and + source.flowsTo(read) + ) + } +} + +private string clientIpParameterName() { + result in [ + "x-forwarded-for", "x_forwarded_for", "x-real-ip", "x_real_ip", "proxy-client-ip", + "proxy_client_ip", "wl-proxy-client-ip", "wl_proxy_client_ip", "http_x_forwarded_for", + "http-x-forwarded-for", "http_x_forwarded", "http_x_cluster_client_ip", "http_client_ip", + "http_forwarded_for", "http_forwarded", "http_via", "remote_addr" + ] +} + +/** A data flow sink for ip address forgery vulnerabilities. */ +abstract class PossibleSecurityCheck extends DataFlow::Node { } + +/** + * A data flow sink for remote client ip comparison. + * + * For example: `if !ip.startsWith("10.")` determine whether the client ip starts + * with `10.`, and the program can be deceived by forging the ip address. + */ +private class CompareSink extends PossibleSecurityCheck { + CompareSink() { + // ip.startsWith("10.") or ip.includes("10.") + exists(CallExpr call | + call.getAChild() = this.asExpr() and + call.getCalleeName() in ["startsWith", "includes"] and + call.getArgument(0).getStringValue().regexpMatch(getIpAddressRegex()) and + not call.getArgument(0).getStringValue() = "0:0:0:0:0:0:0:1" + ) + or + // ip === "127.0.0.1" or ip !== "127.0.0.1" or ip == "127.0.0.1" or or ip != "127.0.0.1" + exists(Comparison compare | + compare instanceof EqualityTest and + ( + [compare, compare.getAnOperand()] = this.asExpr() and + compare.getAnOperand().getStringValue() instanceof PrivateHostName and + not compare.getAnOperand().getStringValue() = "0:0:0:0:0:0:0:1" + ) + ) + } +} + +string getIpAddressRegex() { + result = + "^((10\\.((1\\d{2})?|(2[0-4]\\d)?|(25[0-5])?|([1-9]\\d|[0-9])?)(\\.)?)|(192\\.168\\.)|172\\.(1[6789]|2[0-9]|3[01])\\.)((1\\d{2})?|(2[0-4]\\d)?|(25[0-5])?|([1-9]\\d|[0-9])?)(\\.)?((1\\d{2})?|(2[0-4]\\d)?|(25[0-5])?|([1-9]\\d|[0-9])?)$" +} + +/** + * A string matching private host names of IPv4 and IPv6, which only matches the host portion therefore checking for port is not necessary. + * Several examples are localhost, reserved IPv4 IP addresses including 127.0.0.1, 10.x.x.x, 172.16.x,x, 192.168.x,x, and reserved IPv6 addresses including [0:0:0:0:0:0:0:1] and [::1] + */ +private class PrivateHostName extends string { + bindingset[this] + PrivateHostName() { + this.regexpMatch("(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?") + } +} diff --git a/javascript/ql/src/experimental/Security/CWE-348/examples/ClientSuppliedIpUsedInSecurityCheck.js b/javascript/ql/src/experimental/Security/CWE-348/examples/ClientSuppliedIpUsedInSecurityCheck.js new file mode 100644 index 000000000000..223b79f61534 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-348/examples/ClientSuppliedIpUsedInSecurityCheck.js @@ -0,0 +1,60 @@ +const express = require("express"); +const app = express(); +const port = 3000; + +app.get("/bad1", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + // Bad: use this value directly + if (ip && ip === "127.0.0.1") { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/bad2", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + // Bad: the first IP is used + var temp = ip.split(","); + ip = temp[0]; + + if (ip && ip === "127.0.0.1") { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/good", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + var temp = ip.split(","); + ip = temp[temp.length - 1]; + + if (ip && ip === "127.0.0.1") { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.listen(port, () => { + console.log(`Example app listening at http://localhost:${port}`); +}); diff --git a/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js b/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js new file mode 100644 index 000000000000..6e53c2829a56 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js @@ -0,0 +1,206 @@ +const express = require("express"); +const app = express(); +const port = 3000; + +const getClientIPBad = (req) => { + var ip = req.headers["x-forwarded-for"]; + return ip; +}; + +app.get("/bad1", (req, res) => { + var ip = getClientIPBad(req); + + if (ip && ip === "127.0.0.1") { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/bad2", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + if (ip && ip.startsWith("10.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/bad3", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + if (ip && ip.includes("172.16.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/bad4", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + ip = ip.split(",")[0]; + + if (ip && ip.includes("172.31.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/bad5", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + var temp = ip.split(","); + ip = temp[0]; + + if (ip && ip.includes("192.168.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/false-positive-1", (req, res) => { + var temp = []; + var ip = temp["x-forwarded-for"]; + + if (ip && ip === "127.0.0.1") { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +const getClientIPGood = (req) => { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + return ""; + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + ip = ip.split(",")[ip.split(",").length - 1]; + return ip; +}; + +app.get("/good1", (req, res) => { + var ip = getClientIPGood(req); + + if (ip && ip === "127.0.0.1") { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/good2", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + ip = ip.split(",")[ip.split(",").length - 1]; + + if (ip && ip.startsWith("10.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/good3", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + var temp = ip.split(","); + ip = temp[temp.length - 1]; + + if (ip && ip.includes("172.16.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/good4", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + ip = ip.split(",").pop(); + + if (ip && ip.includes("172.31.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.get("/good5", (req, res) => { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + var temp = ip.split(","); + ip = temp.pop(); + + if (ip && ip.includes("192.168.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + res.end("illegal ip"); +}); + +app.listen(port, () => { + console.log(`Example app listening at http://localhost:${port}`); +}); diff --git a/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js b/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js new file mode 100644 index 000000000000..95fee1fecc48 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js @@ -0,0 +1,187 @@ +const http = require("http"); + +const getClientIPBad = (req) => { + var ip = req.headers["x-forwarded-for"]; + + return ip; +}; + +const getClientIPGood = (req) => { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + return ""; + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + ip = ip.split(",")[ip.split(",").length - 1]; + return ip; +}; + +const requestListener = function (req, res) { + if (req.url === "/bad1") { + var ip = getClientIPBad(req); + + if (ip && ip === "127.0.0.1") { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/bad2") { + var ip = req.headers["x-forwarded-for"]; + + if (ip && ip.startsWith("10.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/bad3") { + var ip = req.headers["x-forwarded-for"]; + + if (ip && ip.includes("172.16.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/bad4") { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + ip = ip.split(",")[0]; + + if (ip && ip.startsWith("172.31.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/bad5") { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + var temp = ip.split(","); + ip = temp[0]; + + if (ip && ip.startsWith("192.168.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/false-positive-1") { + var ip = []["x-forwarded-for"]; + + if (ip && ip.startsWith("10.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/good1") { + var ip = getClientIPGood(req); + + if (ip && ip === "127.0.0.1") { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/good2") { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + ip = ip.split(",")[ip.split(",").length - 1]; + + if (ip && ip.startsWith("10.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/good3") { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + var temp = ip.split(","); + ip = temp[temp.length - 1]; + + if (ip && ip.startsWith("172.16.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/good4") { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + ip = ip.split(",").pop(); + + if (ip && ip.includes("172.31.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else if (req.url === "/good5") { + var ip = req.headers["x-forwarded-for"]; + + if (!ip) { + res.writeHead(403); + return res.end("illegal ip"); + } + + // Good: if this application runs behind a reverse proxy it may append the real remote IP to the end of any client-supplied X-Forwarded-For header. + var temp1 = ip.split(","); + var temp2 = temp1; + ip = temp2.pop(); + + if (ip && ip.includes("192.168.")) { + res.writeHead(200); + return res.end("Hello, World!"); + } + + res.writeHead(403); + return res.end("illegal ip"); + } else { + res.writeHead(404); + res.end("Not Found!"); + } +}; + +const server = http.createServer(requestListener); +server.listen(3000); diff --git a/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.expected b/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.expected new file mode 100644 index 000000000000..288bf31799a8 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.expected @@ -0,0 +1,10 @@ +| ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:13:13:13:14 | ip | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:6:12:6:41 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:13:13:13:14 | ip | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:6:12:6:41 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:25:13:25:25 | ip.startsWith | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:23:12:23:41 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:25:13:25:25 | ip.startsWith | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:23:12:23:41 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:37:13:37:23 | ip.includes | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:35:12:35:41 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:37:13:37:23 | ip.includes | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:35:12:35:41 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:56:13:56:23 | ip.includes | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:47:12:47:41 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:56:13:56:23 | ip.includes | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:47:12:47:41 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:76:13:76:23 | ip.includes | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:66:12:66:41 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:76:13:76:23 | ip.includes | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-ExpressJS.js:66:12:66:41 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:25:15:25:16 | ip | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:4:12:4:41 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:25:15:25:16 | ip | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:4:12:4:41 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:35:15:35:27 | ip.startsWith | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:33:14:33:43 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:35:15:35:27 | ip.startsWith | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:33:14:33:43 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:45:15:45:25 | ip.includes | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:43:14:43:43 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:45:15:45:25 | ip.includes | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:43:14:43:43 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:62:15:62:27 | ip.startsWith | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:53:14:53:43 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:62:15:62:27 | ip.startsWith | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:53:14:53:43 | req.hea ... d-for"] | this user input | +| ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:80:15:80:27 | ip.startsWith | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:70:14:70:43 | req.hea ... d-for"] | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:80:15:80:27 | ip.startsWith | IP address spoofing might include code from $@. | ClientSuppliedIpUsedInSecurityCheck-NodeJSLib.js:70:14:70:43 | req.hea ... d-for"] | this user input | diff --git a/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref b/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref new file mode 100644 index 000000000000..1e83d921856c --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql