Testland
Browse all skills & agents

codeql-queries

Configures and runs GitHub CodeQL - semantic-database SAST with queries written in the CodeQL declarative query language; supports `codeql database create` (per-language) + `codeql database analyze` with --format=sarif; ships query packs (`codeql/javascript-queries`, `codeql/python-queries`, `codeql/java-queries`, `codeql/go-queries`, etc.); integrates with GitHub Code Scanning via SARIF upload; suppression via inline comment + sarif-filter + Security-tab dismissal. Use when the team uses GitHub-hosted repos and needs deep semantic SAST beyond pattern matching (cross-file taint flows, dataflow analysis).

Install with skills.sh (any agent)

npx skills add testland/qa --skill codeql-queries
View source

codeql-queries

Overview

Per docs.github.com/code-security/codeql-cli (opens in new window):

CodeQL is GitHub's semantic-analysis SAST: build a database of the codebase (control flow, data flow, type info), run .ql queries against it, emit SARIF for GitHub Code Scanning. This database-then-query model catches cross-file taint flows (user input reaching a SQL sink unsanitized) that pattern matchers cannot express.

When to use

  • The team uses GitHub-hosted repos (Code Scanning is GitHub-native).
  • The codebase has cross-file taint flows that pattern-matchers miss (e.g., user input → service A → service B → SQL).
  • A security audit requires CodeQL coverage (some compliance regimes prefer it).
  • The team writes custom queries for org-specific patterns.

For multi-platform CI without GitHub, use semgrep-rules or sonarqube-rules.

Step 1 - Install

CodeQL CLI download from github.com/github/codeql-cli-binaries/releases (opens in new window). Per cql-docs (opens in new window) the CLI is bundled separately from the queries - install both:

# Download CodeQL CLI (per platform)
curl -L https://github.com/github/codeql-cli-binaries/releases/latest/download/codeql-linux64.zip -o codeql.zip
unzip codeql.zip
export PATH="$PATH:$PWD/codeql"

# Verify
codeql --version

Query packs (the .ql files) are pulled per-scan via --download flag or pre-installed via codeql pack download.

Step 2 - Create a database

# For interpreted languages (JS, Python, Ruby): no build needed
codeql database create my-db --language=javascript --source-root=.

# For compiled languages (Java, C#, Go): wrap the build
codeql database create my-db --language=java --command="./gradlew build" --source-root=.

codeql database create my-db --language=cpp --command="make all"

The --language flag accepts: cpp / csharp / go / java / javascript / python / ruby / swift / kotlin (verify support against cql-docs (opens in new window) for the current CodeQL release).

For JS/TS + Python, the --build-mode none extraction works without a build step. For Java/C#/C++, you MUST wrap the project's build via --command so CodeQL can observe compilation.

Step 3 - Analyze with query packs

codeql database analyze my-db \
  --format=sarif-latest \
  --output=results.sarif \
  codeql/javascript-queries

The full per-language pack list, the query suites (code-scanning, security-and-quality, security-extended), a custom .ql query example, and the GitHub Actions CI integration are in references/codeql-reference.md.

Step 4 - False-positive triage (MANDATORY)

Three layers:

MechanismExampleWhen to use
Inline // codeql[<rule-id>]// codeql[js/sql-injection] - Reason: input pre-sanitized via library XSingle-line exception with documented rationale
SARIF post-processing filtercat results.sarif | jq 'del(.runs[].results[] | select(.ruleId == "js/path-injection" and .locations[].physicalLocation.artifactLocation.uri | startswith("vendor/")))'Bulk exclusion of vendored / generated code
GitHub Security tab dismissalUI: "Dismiss alert" → False positive / Won't fix / Used in testsPersistent, auditable, requires reviewer comment

Justification template (mandatory in code):

// codeql[js/sql-injection]
// Reason: parameter pre-validated via Joi schema (line 42); literal interpolation safe
// Reviewer: alice@example.com (2026-05-15)
// Expires: 2026-12-15
const result = await db.query(`SELECT * FROM users WHERE id = ${userId}`);

GitHub Security tab dismissals are persistent + auditable + show in the audit log; prefer them over inline comments for production suppressions.

Cadence: every quarter, review GitHub Security → "Dismissed alerts" filter; expired ones reopened for re-review.

Step 5 - Database performance

CodeQL databases can be GBs for large codebases. Performance flags:

codeql database create my-db --language=java \
  --command="./gradlew build" \
  --threads=8 \
  --ram=8192   # MB

For incremental scanning (changed-files-only), GitHub's hosted runner uses caching across runs. Self-hosted CI must implement caching manually (the codeql-action/init action handles it on GitHub).

Anti-patterns

Anti-patternWhy it failsFix
Skip --command for compiled languagesDatabase empty; analysis returns no findings silentlyAlways wrap the build (Step 2)
Use security-extended without baselineFlood of pre-existing findings overwhelms the teamStart with code-scanning; ratchet up
Inline comment without GitHub dismissalNo audit trailUse Security-tab dismissal for persistent FPs (Step 4)
Run CodeQL on every PR for large codebaseDatabase creation is slow (10 - 30 min); PR cycle slowSchedule full scan nightly; PR-only delta scanning via Code Scanning
Custom queries without test suiteBugs in custom queries miss real findingsUse codeql test to validate against expected-results files

Limitations

  • Database creation is slow for large codebases (10 - 30 min on monorepos); incremental scanning helps but requires caching.
  • Custom-query authoring has a steep learning curve; the CodeQL University courses help.
  • Some languages have less depth than others (Go, Ruby, Swift are newer than JS/Java/C++).
  • Self-hosted (non-GitHub) integration requires manual SARIF routing.
  • License: CodeQL CLI is free for open-source repos; commercial use requires GitHub Advanced Security license.

References

  • cql-docs (opens in new window) - CodeQL CLI getting started
  • codeql.github.com/docs - official documentation root
  • codeql.github.com/codeql-standard-libraries/ - per-language stdlibs
  • github.com/github/codeql - query packs source
  • learningqltest.github.io/learningql/ - CodeQL University training
  • semgrep-rules, sonarqube-rules, bandit-python, gosec-go - sister scanners

CodeQL query packs, custom queries, and CI

View source (opens in new window)

CodeQL query packs, custom queries, and CI

Reference detail for codeql-queries. The SKILL.md spine keeps the core create/analyze/triage path; this file holds the full pack list, the custom .ql example, and the GitHub Actions integration. Per docs.github.com/code-security/codeql-cli (opens in new window).

Query packs

PackCoverage
codeql/javascript-queriesJS/TS standard checks
codeql/python-queriesPython checks
codeql/java-queriesJava + Kotlin checks
codeql/go-queriesGo checks
codeql/cpp-queriesC/C++ checks
codeql/csharp-queriesC# checks
codeql/ruby-queriesRuby checks
codeql/swift-queriesSwift checks

Each pack ships query suites: code-scanning (default for GitHub Code Scanning), security-and-quality (broader), security-extended (more rules, more false positives).

codeql database analyze my-db \
  codeql/javascript-queries:codeql-suites/javascript-security-extended.qls \
  --format=sarif-latest \
  --output=results.sarif

Custom query authoring

/**
 * @name Hardcoded JWT secret in jwt.sign call
 * @description Detects jwt.sign() calls with literal-string secret
 * @kind problem
 * @problem.severity error
 * @id js/hardcoded-jwt-secret
 * @tags security
 *       external/cwe/cwe-798
 */

import javascript

from CallExpr call, StringLiteral secret
where
  call.getCalleeName() = "sign" and
  call.getReceiver().(VarRef).getName() = "jwt" and
  call.getArgument(1) = secret
select call, "Hardcoded JWT secret detected: " + secret.getValue()

Custom queries register in a query suite (.qls) for selective execution. Validate them with codeql test against expected-results files.

CI integration (GitHub Actions)

Most teams use the GitHub-hosted action for any GitHub-hosted repo:

jobs:
  codeql:
    runs-on: ubuntu-latest
    permissions:
      security-events: write   # for SARIF upload to Security tab
    steps:
      - uses: actions/checkout@v5
      - uses: github/codeql-action/init@v3
        with:
          languages: javascript, python
          queries: security-extended
      - run: ./gradlew build   # or whatever build step is needed
      - uses: github/codeql-action/analyze@v3
        with:
          category: "/language:javascript"

For non-GitHub CI (GitLab / Jenkins), use the CodeQL CLI directly (create + analyze) and upload SARIF to GitHub Code Scanning via the API or a SARIF-compatible viewer.

Related skills

bandit-python

Configures and runs Bandit - Python-only SAST covering 60+ rule IDs across 7 categories (B1xx-B7xx: misc, app, crypto, imports, injections, XSS); `bandit -r .` scan, `--severity-level` + `--confidence-level` filtering, `# nosec`/`# nosec B404` per-line and per-rule suppression, `pyproject.toml [tool.bandit]` config. Use for a focused, low-overhead Python SAST in pre-commit / CI. Python-only: for Go use gosec-go, for cross-language pattern SAST use semgrep-rules; to merge Bandit findings with other scanners into one gate use multi-tool-finding-triage - not this for non-Python code.

eslint-security-rules

Configures and runs `eslint-plugin-security` (14 detect-* rules covering injection, path traversal, ReDoS, unsafe buffers, and bidi trojan-source) plus `eslint-plugin-no-unsanitized` (DOM XSS via `innerHTML`, `outerHTML`, `document.write`, `insertAdjacentHTML`) as the JS/TS first-party SAST layer; covers flat config setup, per-rule suppression with justification templates, SARIF output via `@microsoft/eslint-formatter-sarif` for GitHub Code Scanning upload, and CI gating on ESLint exit code 1. Use when the project is JS or TS and needs an in-process security lint pass without a separate SAST server.

gosec-go

Configures and runs gosec - Go-only SAST covering 40+ rule IDs (G101 hardcoded creds, G104 unhandled errors, G304 path traversal, G401 weak crypto, G601 memory aliasing) via Go AST + SSA taint tracking; `gosec ./...` scan, `#nosec G404 -- justification` suppression, `--fmt sarif|json|junit-xml|html`, golangci-lint integration. Use for a focused Go SAST wired into golangci-lint / CI. Go-only: for Python use bandit-python, for cross-language pattern SAST use semgrep-rules; to merge gosec findings with other scanners into one gate use multi-tool-finding-triage - not this for non-Go code.

multi-tool-finding-triage

Merges two or more security scanner reports into one gate. Use when you need a single BLOCK or PASS decision from multiple scanners instead of reading N separate reports. Normalizes each report into one common finding format (a canonical `Finding`), deduplicates on a per-domain key while recording which scanners agree (`caught_by` consensus), validates a waiver (finding-suppression) file, rejecting any missing `expires:` / `approved_by:` / `reason:` or expired, enriches CVE findings with EPSS (exploit-probability) and CISA KEV (known-exploited catalog), then applies a `fail_on` severity threshold to emit BLOCK or PASS plus a bucketed pull-request comment. Works across static (SAST), dynamic (DAST), secret, dependency (SCA), container, and IaC scanners. To run a single scanner instead use semgrep-rules, codeql-queries, bandit-python, or gosec-go; this runs after them to merge output - the cross-scanner gate, not a single-scanner wrapper.

pmd-apex-rules

Runs PMD's built-in Apex security ruleset (`category/apex/security.xml`) against Salesforce Apex source to detect injection, privilege-escalation, cryptographic, and XSS vulnerabilities; configures custom rulesets for regulated-industry Apex codebases; emits SARIF for GitHub Code Scanning upload; integrates `pmd check` as a PR-blocking CI gate. Use when the codebase contains Salesforce Apex and the team needs SAST coverage for ApexSOQLInjection, ApexCRUDViolation, ApexSharingViolations, or the full 10-rule security category.

semgrep-rules

Configures and runs Semgrep - pattern-based SAST across 30+ languages with the Semgrep Registry rulesets (`p/owasp-top-ten`, `p/default`, `auto`) plus custom YAML rules; integrates `semgrep ci` for PR-blocking gates with `--baseline-commit` diff-aware scanning, per-finding inline `nosemgrep` suppressions, `--exclude` / `--include` path filters, output formats (`--json` / `--sarif` / `--gitlab-sast` / `--junit-xml`), and severity filter (INFO/WARNING/ERROR). Use when the user runs Semgrep, asks about pattern rules, or needs a low-friction SAST gate without semantic-DB setup.

sonarqube-rules

Configures and runs SonarQube / SonarCloud - multi-language SAST + Quality Gate platform with built-in Sonar Way rule profiles + custom rule plugins; integrates `sonar-scanner` with `sonar-project.properties` config; supports Quality Gate definitions including new-code-period blocking, branch + PR analysis, and per-issue suppression via `// NOSONAR` comment or `@SuppressWarnings("squid:RULE_ID")` annotation. Use when the user runs SonarQube Community / Developer / Enterprise edition or SonarCloud, or needs a multi-language SAST + code-quality platform with persistent issue tracking.