**Ideal scenarios:** - Source code access with ability to build (for compiled languages) - Open-source projects or GitHub Advanced Security license
HTTP Handler → Input Parser → Business Logic → Database Query ↓ ↓ ↓ ↓ source transforms passes sink (SQL)
request.param in file A to db.execute(query) in file B.# Check if CodeQL is installed command -v codeql >/dev/null 2>&1 && echo "CodeQL: installed" || echo "CodeQL: NOT installed (run install steps below)"
# macOS/Linux (Homebrew) brew install --cask codeql # Update brew upgrade codeql
# Download ToB query packs codeql pack download trailofbits/cpp-queries trailofbits/go-queries # Verify installation codeql resolve qlpacks | grep trailofbits
codeql database create codeql.db --language=<LANG> [--command='<BUILD>'] --source-root=.--language=pythonjavascriptgorubyrust--command='cargo build')java--command='./gradlew build')cpp--command='make -j8')csharp--command='dotnet build')swift# List available query packs codeql resolve qlpacks `**Run security queries:**` # SARIF output (recommended) codeql database analyze codeql.db \ --format=sarif-latest \ --output=results.sarif \ -- codeql/python-queries:codeql-suites/python-security-extended.qls # CSV output codeql database analyze codeql.db \ --format=csv \ --output=results.csv \ -- codeql/javascript-queries `**With Trail of Bits queries (if installed):**` codeql database analyze codeql.db \ --format=sarif-latest \ --output=results.sarif \ -- trailofbits/go-queries
from Type x where P(x) select f(x)/** * @name Find SQL injection vulnerabilities * @description Identifies potential SQL injection from user input * @kind path-problem * @problem.severity error * @security-severity 9.0 * @precision high * @id py/sql-injection * @tags security * external/cwe/cwe-089 */ import python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking module SqlInjectionConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { // Define taint sources (user input) exists(source) } predicate isSink(DataFlow::Node sink) { // Define dangerous sinks (SQL execution) exists(sink) } } module SqlInjectionFlow = TaintTracking::Global<SqlInjectionConfig>; from SqlInjectionFlow::PathNode source, SqlInjectionFlow::PathNode sink where SqlInjectionFlow::flowPath(source, sink) select sink.getNode(), source, sink, "SQL injection from $@.", source.getNode(), "user input"
@kindproblem, path-problem@problem.severityerror, warning, recommendation@security-severity0.0 - 10.0@precisionvery-high, high, medium, low// Predicates predicate isUserInput(DataFlow::Node node) { exists(Call c | c.getFunc().(Attribute).getName() = "get" and node.asExpr() = c) } // Transitive closure: + (one or more), * (zero or more) node.getASuccessor+() // Quantification exists(Variable v | v.getName() = "password") forall(Call c | c.getTarget().hasName("dangerous") | hasCheck(c)) `## Creating Query Packs` codeql pack init myorg/security-queries `Structure:` myorg-security-queries/ ├── qlpack.yml ├── src/ │ └── SqlInjection.ql └── test/ └── SqlInjectionTest.expected `**qlpack.yml:**` name: myorg/security-queries version: 1.0.0 dependencies: codeql/python-all: "*" `## CI/CD Integration (GitHub Actions)` name: CodeQL Analysis on: push: branches: [main] pull_request: branches: [main] schedule: - cron: '0 0 * * 1' # Weekly jobs: analyze: runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: matrix: language: ['python', 'javascript'] steps: - uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: security-extended,security-and-quality # Add custom queries/packs: # queries: security-extended,./codeql/custom-queries # packs: trailofbits/python-queries - uses: github/codeql-action/autobuild@v3 - uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" `## Testing Queries` codeql test run test/ `Test file format:` def vulnerable(): user_input = request.args.get("q") # Source cursor.execute("SELECT * FROM users WHERE id = " + user_input) # Alert: sql-injection def safe(): user_input = request.args.get("q") cursor.execute("SELECT * FROM users WHERE id = ?", (user_input,)) # OK
--threads, narrow query scope, check query complexityCODEQL_RAM=48000 environment variable (48GB)--source-root to point to actual source location