diff --git a/java/ql/lib/semmle/code/java/security/StackTraceExposureQuery.qll b/java/ql/lib/semmle/code/java/security/StackTraceExposureQuery.qll index 0eb069a06c20..6c6435709632 100644 --- a/java/ql/lib/semmle/code/java/security/StackTraceExposureQuery.qll +++ b/java/ql/lib/semmle/code/java/security/StackTraceExposureQuery.qll @@ -70,6 +70,16 @@ private module StackTraceStringToHttpResponseSinkFlowConfig implements DataFlow: predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) } predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink } + + predicate isBarrier(DataFlow::Node node) { + exists(MethodCall logCall | + node.asExpr() = logCall.getAnArgument() and + logCall.getMethod().getDeclaringType().hasQualifiedName(["org.slf4j", "org.apache.logging.log4j", "org.apache.log4j", "java.util.logging"], + ["Logger", "Log", "LogRecord"]) and + logCall.getMethod().getName() in ["trace", "debug", "info", "warn", "error", "fatal", "log", + "severe", "warning", "fine", "finer", "finest"] + ) + } } private module StackTraceStringToHttpResponseSinkFlow = diff --git a/java/ql/test/query-tests/security/CWE-209/semmle/tests/StackTraceLoggingTest.java b/java/ql/test/query-tests/security/CWE-209/semmle/tests/StackTraceLoggingTest.java new file mode 100644 index 000000000000..10e4859f32dc --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-209/semmle/tests/StackTraceLoggingTest.java @@ -0,0 +1,38 @@ +package test.cwe209.semmle.tests; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test that stack traces logged to internal logging frameworks are not + * flagged as information exposure. + */ +class StackTraceLoggingTest extends HttpServlet { + private static final Logger logger = LoggerFactory.getLogger(StackTraceLoggingTest.class); + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + try { + doSomeWork(); + } catch (Exception ex) { + // GOOD: stack trace is logged internally, not exposed to user + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + ex.printStackTrace(pw); + String stackTrace = sw.toString(); + logger.error("Internal error: {}", stackTrace); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An error occurred"); + } + } + + private void doSomeWork() throws Exception { + throw new Exception("test"); + } +}