diff --git a/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql b/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql index 3426d9f6f62..b82edc2efc6 100644 --- a/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql +++ b/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql @@ -16,6 +16,7 @@ import java import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.TaintTracking import semmle.code.java.security.XSS +import semmle.code.java.security.InformationLeak /** * One of the `printStackTrace()` overloads on `Throwable`. @@ -83,14 +84,17 @@ predicate stackTraceExpr(Expr exception, MethodAccess stackTraceString) { ) } -class StackTraceStringToXssSinkFlowConfig extends TaintTracking::Configuration { - StackTraceStringToXssSinkFlowConfig() { - this = "StackTraceExposure::StackTraceStringToXssSinkFlowConfig" +class StackTraceStringToHTTPResponseSinkFlowConfig extends TaintTracking::Configuration { + StackTraceStringToHTTPResponseSinkFlowConfig() { + this = "StackTraceExposure::StackTraceStringToHTTPResponseSinkFlowConfig" } override predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) } - override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } + override predicate isSink(DataFlow::Node sink) { + sink instanceof XssSink or + sink instanceof InformationLeakSink + } } /** @@ -106,7 +110,7 @@ predicate printsStackExternally(MethodAccess call, Expr stackTrace) { * A stringified stack trace flows to an external sink. */ predicate stringifiedStackFlowsExternally(XssSink externalExpr, Expr stackTrace) { - exists(MethodAccess stackTraceString, StackTraceStringToXssSinkFlowConfig conf | + exists(MethodAccess stackTraceString, StackTraceStringToHTTPResponseSinkFlowConfig conf | stackTraceExpr(stackTrace, stackTraceString) and conf.hasFlow(DataFlow::exprNode(stackTraceString), externalExpr) ) diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 33a146d07fe..92dfb5a733c 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -79,6 +79,7 @@ private module Frameworks { private import semmle.code.java.frameworks.guava.Guava private import semmle.code.java.frameworks.jackson.JacksonSerializability private import semmle.code.java.security.ResponseSplitting + private import semmle.code.java.security.InformationLeak private import semmle.code.java.security.XSS private import semmle.code.java.security.LdapInjection private import semmle.code.java.security.XPath diff --git a/java/ql/src/semmle/code/java/security/InformationLeak.qll b/java/ql/src/semmle/code/java/security/InformationLeak.qll new file mode 100644 index 00000000000..4cb12c3d3d9 --- /dev/null +++ b/java/ql/src/semmle/code/java/security/InformationLeak.qll @@ -0,0 +1,23 @@ +/** Provides classes to reason about System Information Leak vulnerabilities. */ + +import java +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.ExternalFlow + +/** CSV sink models representing methods not susceptible to XSS but outputing to an HTTP response body. */ +private class DefaultInformationLeakSinkModel extends SinkModelCsv { + override predicate row(string row) { + row = + [ + "javax.servlet.http;HttpServletResponse;false;sendError;(int,String);;Argument[1];information-leak" + ] + } +} + +/** A sink that represent a method that outputs data to an HTTP response. */ +abstract class InformationLeakSink extends DataFlow::Node { } + +/** A default sink representing methods outputing data to an HTTP response. */ +private class DefaultInformationLeakSink extends InformationLeakSink { + DefaultInformationLeakSink() { sinkNode(this, "information-leak") } +}