Files
codeql-lab/codeql-jedis

Jedis Codeql Setup

  • fork at https://github.com/hohn/jedis
  • github db build: enable code scanning, advanced config

  • local db build:

      cd ~/work-gh/codeql-lab/
    
      # Add the submodule
      git submodule add https://github.com/hohn/jedis extern/jedis
    
      # Initialize and clone the submodule
      git submodule update --init --recursive
    
    
      # Build directly once to resolve any errors
      cd ~/work-gh/codeql-lab/extern/jedis
      mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
    
      # Build under codeql
      # Step 1: Clean any prior Maven builds
      cd ~/work-gh/codeql-lab/extern/jedis
      mvn clean
    
      # Step 2: Run CodeQL DB creation with mvn install
      cd ~/work-gh/codeql-lab
      codeql database create assets/jedis-db-local \
             --overwrite \
             --language=java \
             --command="mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V" \
             --source-root=extern/jedis

Jedis Codeql Modeling

Setup and Start

  # Step 1: Go to your CodeQL lab directory
  cd ~/work-gh/codeql-lab

  # Step 2: Extract the prebuilt CodeQL database for the Jedis project
  unzip -q assets/jedis-db-local.zip

  # Step 3: Extract the CodeQL command-line tools (platform-specific)
  unzip -q assets/codeql-osx64.zip

  # Step 4: Change directory to the unpacked CodeQL CLI tools
  cd ~/work-gh/codeql-lab/codeql

  # Step 5: Add the CodeQL CLI directory to your shell's PATH
  # This allows you to run `codeql` from any location
  export PATH="$(pwd):$PATH"

  # Step 6: Launch Visual Studio Code with the lab workspace
  code qllab.code-workspace

  # In VS Code, perform the following setup manually:
  # - Set the current database to: jedis-db-local
  #   (Usually from the CodeQL extension pane  this connects the UI to your analysis DB)
  # - Set the CodeQL CLI executable to: ~/work-gh/codeql-lab/codeql/codeql
  #   (Tell the extension where to find the CLI you just extracted)
  # - In the CodeQL extension tab, scroll to the bottom and select:
  #   'CodeQL: Method modeling' to begin a guided modeling tutorial

Using the Editor

Note that just by starting CodeQL: Method modeling, the new file

.github/codeql/extensions/jedis-db-local-java/codeql-pack.yml

is created.

Relevant Queries

A quick grep shows

  grep 'java.*modelgen' files  |grep -v test/

  ql/java/ql/src/utils/modelgenerator
  ql/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
  ql/java/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
  ql/java/ql/src/utils/modelgenerator/CaptureSinkModels.ql
  ql/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql
  ql/java/ql/src/utils/modelgenerator/internal
  ql/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll
  ql/java/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll
  ql/java/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll
  ql/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
  ql/java/ql/src/utils/modelgenerator/RegenerateModels.py
  ql/java/ql/src/utils/modelgenerator/CaptureSourceModels.ql
  ql/java/ql/src/utils/modelgenerator/debug
  ql/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql
  ql/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql
  ql/java/ql/src/utils/modelgenerator/debug/README.md

Primary Query File

The primary query file is

../ql/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll

This acts as the backbone, exposing traits like:

  • SummaryModelGeneratorInput
  • ModelGeneratorCommonInput
  • isPrimitiveTypeUsedForBulkData(…)
  • Likely common predicates such as:

    • hasNoSideEffects(…)
    • isNeutralReturn(…)
    • isBulkGetterLike(…)

    These are imported by:

    • CaptureSinkModels.ql
    • CaptureSummaryModels.ql
    • CaptureContentSummaryModels.ql
    • CaptureHeuristicSummaryModels.ql
  • Design: Three Modeling Targets

    Module Implements Purpose
    —————————- ——————————- ————————————————
    `SummaryModelGeneratorInput` `SummaryModelGeneratorInputSig` Models pass-through or computed summaries
    `SourceModelGeneratorInput` `SourceModelGeneratorInputSig` Models user-controlled or origin taint sources
    `SinkModelGeneratorInput` `SinkModelGeneratorInputSig` Models taint sinks (e.g., logging, SQL, network)
  • Shared Input System ModelGeneratorCommonInput provides:

    • Name formatting
    • Type filtering (isRelevantType)
    • Signature stringification
    • “Approximate output” helpers like Argument[pos].Element

    This gives a stable data interface to the rest of the system.

  • Filtering logic

      private predicate relevant(Callable api) {
        api.isPublic() and
        api.getDeclaringType().isPublic() and
        api.fromSource() and
        not isUninterestingForModels(api) and
        not isInfrequentlyUsed(api.getCompilationUnit())
      }

Experiment with test clone

The needed imports are private, so clone

ql/java/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.ql

and experiment there.

  import java
  import utils.modelgenerator.internal.CaptureModels
  import SourceModels
  import utils.test.InlineMadTest

  module InlineMadTestConfig implements InlineMadTestConfigSig {
    string getCapturedModel(Callable c) { result = Heuristic::captureSource(c) }

    string getKind() { result = "source" }
  }

  import InlineMadTest<InlineMadTestConfig>

Modeling sqlite as dependency

The tree

src-sqlite

contains a trivial sample taken from a workshop. It uses sqlite-jdbc-3.36.0.1.jar, so we can use it to illustrate modeling on a smaller example.

Modeling jedis as dependency

Running the model editor a jedis db models jedis dependencies; we need jedis as dependency to model it.

Using the

  • model as depedency option

the query run by model editor is

/Users/hohn/work-gh/codeql-lab/ql/java/ql/src/utils/modeleditor/FrameworkModeEndpoints.ql

The columns of the query

  from PublicEndpointFromSource endpoint, boolean supported, string type
  where
    supported = isSupported(endpoint) and
    type = supportedType(endpoint)
  select endpoint, endpoint.getPackageName(), endpoint.getTypeName(), endpoint.getName(),
    endpoint.getParameterTypes(), supported,
    endpoint.getCompilationUnit().getParentContainer().getBaseName(), type

indicate the modeling state:

supported == true
shows as 'Method already modeled' in the editor
supported == false
shows as 'Unmodeled' in the editor

Files involved:

  • Note that just by starting CodeQL: Method modeling, the new file

    .github/codeql/extensions/jedis-db-local-java/codeql-pack.yml
    

    is created.

  • After selection and saving, results are in

    ~/work-gh/codeql-lab/.github/codeql/extensions/jedis-db-local-java/models/redis.clients.jedis.model.yml
    

    The sink added:

      extensions:
        ...
        - addsTo:
            pack: codeql/java-all
            extensible: sinkModel
          data:
            - ["redis.clients.jedis","Jedis",true,"eval","(String)","","Argument[0]","code-injection","manual"]
        ...

For the files to be picked up requires the entry

"codeQL.runningQueries.useExtensionPacks": "all"

in

/Users/hohn/work-gh/codeql-lab/qllab.code-workspace
  {
      "folders": [
          {
              "path": "."
          }
      ],
      "settings": {
          "omnisharp.autoStart": false,
          "codeQL.githubDatabase.download": "never",
          "sarif-viewer.connectToGithubCodeScanning": "off",
          "codeQL.cli.executablePath": "/Users/hohn/work-gh/codeql-lab/codeql/codeql",
          "codeQL.runningQueries.useExtensionPacks": "all"
      }
  }

In some cases (older vs code?), the file

/Users/hohn/work-gh/codeql-lab/.vscode/settings.json

needs that entry.

With the additions from the model editor, the query

  import java
  private import semmle.code.java.dataflow.ExternalFlow
  private import semmle.code.java.dataflow.DataFlow

  from DataFlow::Node n, string type
  where sinkNode(n, type) 
  and type = "code-injection"
  select n, type

lists the sink arguments to eval():

example.ql on jedis-db-local - finished in 2 seconds (14 results) [7/8/2025, 12:51:20 PM]

1 script code-injection
2 getBytes(…) code-injection
3 script code-injection
4 script code-injection
5 script code-injection
6 script code-injection
7 "return redis.call('get','foo')" code-injection
8 "return redis.call('get','foo')" code-injection
9 encode(…) code-injection
10 encode(…) code-injection
11 "return redis.call('get','foo')" code-injection
12 "return redis.call('get','foo')" code-injection
13 script code-injection
14 "return {}" code-injection

TODO Use of the models in existing queries can be checked

  rg -l -- '-injection' ql/java |grep '\.qll*'

  hohn@ghm3 ~/work-gh/codeql-lab
  2:$ rg -l -- '-injection' ql/java |grep '\.qll*'
  ql/java/ql/src/Security/CWE/CWE-643/XPathInjection.ql
  ql/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql
  ql/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql
  ql/java/ql/src/Security/CWE/CWE-117/LogInjection.ql
  ql/java/ql/src/Security/CWE/CWE-470/FragmentInjection.ql
  ql/java/ql/src/Security/CWE/CWE-470/FragmentInjectionInPreferenceActivity.ql
  ql/java/ql/src/Security/CWE/CWE-730/RegexInjection.ql
  ql/java/ql/lib/semmle/code/java/security/XsltInjection.qll
  ql/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql
  ql/java/ql/lib/semmle/code/java/security/GroovyInjection.qll
  ql/java/ql/lib/semmle/code/java/security/XPath.qll
  ql/java/ql/lib/semmle/code/java/security/TaintedEnvironmentVariableQuery.qll
  ql/java/ql/src/Security/CWE/CWE-074/XsltInjection.ql
  ql/java/ql/src/Security/CWE/CWE-074/JndiInjection.ql
  ql/java/ql/lib/semmle/code/java/security/MvelInjection.qll
  ql/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql
  ql/java/ql/lib/semmle/code/java/security/QueryInjection.qll
  ql/java/ql/lib/semmle/code/java/security/CsrfUnprotectedRequestTypeQuery.qll
  ql/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll
  ql/java/ql/src/Security/CWE/CWE-917/OgnlInjection.ql
  ql/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll
  ql/java/ql/lib/semmle/code/java/security/LdapInjection.qll
  ql/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll
  ql/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll
  ql/java/ql/lib/semmle/code/java/security/LogInjection.qll
  ql/java/ql/lib/semmle/code/java/security/TemplateInjection.qll
  ql/java/ql/lib/ext/org.apache.hadoop.hive.ql.metadata.model.yml
  ql/java/ql/lib/semmle/code/java/security/XSS.qll
  ql/java/ql/lib/semmle/code/java/security/JndiInjection.qll
  ql/java/ql/lib/semmle/code/java/security/FragmentInjection.qll
  ql/java/ql/lib/semmle/code/java/security/CommandLineQuery.qll
  ql/java/ql/src/Security/CWE/CWE-094/SpelInjection.ql
  ql/java/ql/lib/semmle/code/java/security/CleartextStorageAndroidFilesystemQuery.qll
  ql/java/ql/src/Security/CWE/CWE-094/JexlInjection.ql
  ql/java/ql/src/Security/CWE/CWE-094/MvelInjection.ql
  ql/java/ql/src/Security/CWE/CWE-094/TemplateInjection.ql
  ql/java/ql/src/Security/CWE/CWE-094/GroovyInjection.ql
  ql/java/ql/lib/semmle/code/java/security/OgnlInjection.qll
  ql/java/ql/src/experimental/Security/CWE/CWE-078/CommandInjectionRuntimeExecLocal.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-078/CommandInjectionRuntimeExec.ql
  ql/java/ql/lib/ext/org.apache.hadoop.hive.ql.exec.model.yml
  ql/java/ql/src/experimental/Security/CWE/CWE-078/ExecTainted.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.ql
  ql/java/ql/src/Frameworks/Spring/Violations of Best Practice/UseSetterInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-094/JythonInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-094/JShellInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-200/AndroidFileIntentSink.qll
  ql/java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-089/MyBatisMapperXmlSqlInjection.ql
  ql/java/ql/src/experimental/Security/CWE/CWE-089/MyBatisAnnotationSqlInjection.ql
  ql/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll
  hohn@ghm3 ~/work-gh/codeql-lab
  0:$ rg -l -- '-injection' ql/cpp |grep '\.qll*'
  ql/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql
  ql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
  ql/cpp/ql/src/experimental/Security/CWE/CWE-078/WordexpTainted.ql
  ql/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql

TODO for java, the sqltainted query will find the sink, not the source yet.

TODO vulnerable sample

For .eval() to show in a query, it has to be used in an application. So we modify src-sqlite/AddUser.java for jedis.