Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

Java: Detecting flow through throw - catch statements

未關閉
#19,336 2 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

評估

難度
4/5
預估耗時
3-5 天
新手友好度
30/100
Issue 類型
缺陷
描述清晰度
需要釐清
活躍度
停滯
技術堆疊
java
領域
devtools, security

研究方向

從 qlpack.yml 和 codeql-pack.lock.yml 開始,接著針對 toy Java example 檢查 query 的 isSource、isSink 和 isAdditionalFlowStep entry points。使用指定的 CLI 版本執行 query,並驗證是否偵測到 throw-to-catch flow;完成的標準是找出導致 missing flow 的 dependency 或 query behavior。

由索引模型根據 Issue 內容生成。

描述

question

Hello,

I'm having a confusing issue trying to track the data flow from a throw to a catch statement. I had similar queries working just fine. However, I was messing around with my qlpack last week and I think I may have messed something up. To give you some context, I am using CLI version 2.20.3 and here is my

qlpack.yml

---
library: false
warnOnImplicitThis: false
name: custom-codeql-queries
version: 0.0.1
dependencies:
  # codeql/java-queries: ^0.8.9
  codeql/java-all: 6.1.0
libraries:
  - name: SensitiveInfo
    path: /SensitiveInfo
dataExtensions:
  - SensitiveInfo/*.yml

Along with my codeql-pack.lock.yml

---
lockVersion: 1.0.0
dependencies:
  codeql/dataflow:
    version: 1.1.9
  codeql/java-all:
    version: 6.1.0
  codeql/mad:
    version: 1.0.15
  codeql/rangeanalysis:
    version: 1.0.15
  codeql/regex:
    version: 1.0.15
  codeql/ssa:
    version: 1.0.15
  codeql/threat-models:
    version: 1.0.15
  codeql/tutorial:
    version: 1.0.15
  codeql/typeflow:
    version: 1.0.15
  codeql/typetracking:
    version: 1.0.15
  codeql/util:
    version: 2.0.2
  codeql/xml:
    version: 1.0.15
compiled: false

I don't fully understand all of the dependency versions needed to work with my CLI version so I would appriacte it if someones could point out if this looks wrong.

On to my specific issue.

I am trying to detect this toy example.

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ejb.EJBException;
import java.io.IOException;

public class BAD_AuthenticationFailureServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        try {
            authenticateUser(username, password);
        } catch (EJBException e) {
            response.getWriter().write("Authentication failed: " + e.getMessage());
        }
    }

    private void authenticateUser(String username, String password) throws EJBException {
        if (username == null || password == null) {
            throw new EJBException("Username or password is null. Provided username: " + username + ", password: " + password);
        }
        throw new EJBException("Invalid credentials provided for user " + username + ". Attempted password: " + password);
    }
}

With this query

/**
 * @name CWE-550: Exposure of sensitive information through servlet responses
 * @description Detects flows of the `password` parameter into EJBException messages that are written back to HTTP clients.
 * @kind path-problem
 * @problem.severity warning
 * @id java/servlet-info-exposure/550
 * @tags security
 *       external/cwe/cwe-550
 *       external/cwe/cwe-200
 * @cwe CWE-550
 */

 import java
 import semmle.code.java.dataflow.TaintTracking
 import semmle.code.java.dataflow.DataFlow
 
 // Define flow states
 private newtype MyFlowState =
   State1() or
   State2() or
   State3()
 
 module ServerGeneratedErrorMessageConfig implements DataFlow::StateConfigSig {
   class FlowState = MyFlowState;
 
     // Source: the `password` servlet parameter
   predicate isSource(DataFlow::Node source, FlowState state) {
     state instanceof State1 and
     exists(VarAccess va |
       va.getVariable().getName() = "password" and
       source.asExpr() = va
     )
   }
 
 
   // Sink: explicit HTTP response sinks that expose the message
   predicate isSink(DataFlow::Node sink, FlowState state) {
     state instanceof State3 and (
       // response.getWriter().write(msg)
       exists(MethodCall mc |
         mc.getMethod().getName() = "write" and
         exists(MethodCall getWriter |
           getWriter.getMethod().getName() = "getWriter" and
           getWriter = mc.getQualifier() and
           getWriter.getQualifier().getType().(RefType).hasQualifiedName("javax.servlet.http", "HttpServletResponse")
         ) and
         mc.getArgument(0) = sink.asExpr()
       )
     )
   }
 
   // Transitions between flow states
   predicate isAdditionalFlowStep(
     DataFlow::Node node1, FlowState state1,
     DataFlow::Node node2, FlowState state2
   ) {
     // State1->State2: flows into EJBException constructor
     state1 instanceof State1 and state2 instanceof State2 and
     exists(ConstructorCall cc |
       cc.getAnArgument() = node1.asExpr() and
       cc.getConstructor().getDeclaringType().(RefType)
         .getASupertype+().hasQualifiedName("javax.ejb", "EJBException") and
       node2.asExpr() = cc
     )
     or
     // State2->State3: flows from throw to catch capturing e or e.getMessage()
     state1 instanceof State2 and state2 instanceof State3 and
     exists(ThrowStmt t, CatchClause cc, Expr use |
       t.getExpr() = node1.asExpr() and
       cc.getEnclosingCallable() = t.getEnclosingCallable() and
       (
         use = cc.getVariable().getAnAccess()
         or
         exists(MethodCall mc2 |
           mc2.getQualifier() = cc.getVariable().getAnAccess() and
           mc2.getMethod().getName() = "getMessage" and
           use = mc2
         )
       ) and
       node2.asExpr() = use
     )
   }
 }
 
 module SensitiveInfoInErrorMsgFlow =
   TaintTracking::GlobalWithState<ServerGeneratedErrorMessageConfig>;
 import SensitiveInfoInErrorMsgFlow::PathGraph
 
 from SensitiveInfoInErrorMsgFlow::PathNode source, SensitiveInfoInErrorMsgFlow::PathNode sink
 where SensitiveInfoInErrorMsgFlow::flowPath(source, sink)
 select sink, source, sink,
   "CWE-550: password parameter is exposed via server error message."

I have confirmed that the isSource and isSink do work. So the issue is likely in the flow between them. I have used a few queries in the past that follow this similar structure. However, they are also missing some cases randomly at the moment. Which is leading me to believe it has something to do with my qlpack.

As always, thank you for the help.

主要語言
CodeQL
星號
10.1k
分支
2.1k
平均合併
2 天 17 小時
30 天內合併 PR
145

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

github/codeql 的其他 Issue

查看 github/codeql 的全部 Issue

相似的 Issue

更多 DevTools Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。