Skip to content

Determining if an error message is sensitive? #17094

Closed as not planned
Closed as not planned
@KylerKatz

Description

@KylerKatz

Hello, I am currently trying to create a query that will allow me to determine whether a servlet message contains sensitive information.

import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.frameworks.Servlets
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.DataFlow
import CommonSinks.CommonSinks
import SensitiveInfo.SensitiveInfo

module Flow = TaintTracking::Global<SensitiveInfoLeakServletConfig>;

import Flow::PathGraph

module SensitiveInfoLeakServletConfig implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node source) {
    exists(SensitiveVariableExpr sve | source.asExpr() = sve) // Assume this has a list of sensitive variables in a file
    or     exists(CatchClause cc, MethodCall mc | mc.getQualifier() = cc.getVariable().getAnAccess() and source.asExpr() = mc)

  }

  predicate isSink(DataFlow::Node sink) {
    // Consider the case where the sink exposes sensitive info within a catch clause of type ServletException
    exists(CatchClause cc, MethodCall mc |
      // Ensure the CatchClause is catching ServletException
      cc.getACaughtType().hasQualifiedName("javax.servlet", "ServletException") and
      // Ensure the MethodCall is within the CatchClause for the ServletException
      mc.getEnclosingStmt().getEnclosingStmt*() = cc.getBlock() and
      // Ensure the sink matches one of the known sensitive sinks
      (
        getSinkAny(sink)
      ) and
      // Link the sink to the argument of the MethodCall
      sink.asExpr() = mc.getAnArgument()
    )
  }
}

from Flow::PathNode source, Flow::PathNode sink
where Flow::flowPath(source, sink)
select sink.getNode(), source, sink,
  "Servlet Runtime Error Message Containing Sensitive Information."

I almost have this working, however, the issue that I am having has to do with false positives.

Say I have this code

throw new ServletException("Invalid database connection parameters" + dbUrl + dbUser + dbPass);

 } catch (ServletException e) {
  // Catch the ServletException and send an error response
   response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An error occurred while processing the request: " + e.getMessage());
}

In this example, there is sensitive information (dbUrl + dbUser + dbPass) in the e.getMessage() so this would be valid.

However, say we change it to

throw new ServletException("Invalid database connection parameters");

 } catch (ServletException e) {
  // Catch the ServletException and send an error response
   response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An error occurred while processing the request: " + e.getMessage());
}

Now we no longer have sensitive information exposed. However, I am still detecting this. I believe this issue is in this line.

    exists(CatchClause cc, MethodCall mc | mc.getQualifier() = cc.getVariable().getAnAccess() and source.asExpr() = mc)

Without it, I don't detect any usages of e.getMessage(), but with it, I detect all of them. When I only want to detect them with sensitive information in them. I believe this should be moved to the isSink check, however, I am not sure how to integrate it.

I appreciate any help, thank you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Staleawaiting-responseThe CodeQL team is awaiting further input or clarification from the original reporter of this issue.questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions