CodeQL 2.26.3 changes what GitHub code scanning can see in JavaScript, TypeScript, Vue, Sails, and GitHub Actions. Most GitHub.com users receive the engine automatically, but teams with custom queries or alert baselines still need to review the result. A scan that finishes successfully can produce new alerts, remove old false positives, or fail custom query compilation after an API removal.

The most important breaking change is the removal of codeql.actions.security.SelfHostedQuery. Runner labels do not reliably prove whether a job runs on a self-hosted or GitHub-managed runner, so custom queries relying on that module must be changed. The release also improves modeling for merge queues, cache poisoning, environment-variable injection, Vue Router, Sails Action2, promise-wrapped responses, and Fastify rate limiting.

Establish which CodeQL version you actually run

GitHub.com automatically deploys new CodeQL versions to code scanning, while GitHub Enterprise Server receives them in later releases. Advanced setups may pin an Action or bundle version. Before comparing alerts, inspect the workflow and the analysis logs rather than assuming every repository updated at the same time.

name: CodeQL

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  merge_group:

jobs:
  analyze:
    permissions:
      security-events: write
      packages: read
      contents: read
    uses: github/codeql-action/.github/workflows/codeql.yml@v4

Record the workflow commit, CodeQL Action version, query suites, languages, custom query packs, and runner type. If a later alert differs, these details tell you whether the cause was the engine, query pack, workflow, source code, or build environment.

Fix custom queries that use SelfHostedQuery

Search your query repositories and packs before the rollout:

rg "SelfHostedQuery|codeql\.actions\.security" .github codeql security

Any match importing codeql.actions.security.SelfHostedQuery needs review. Do not replace it with another test of runs-on labels and assume the security boundary is restored. Labels are configuration data, and organizations can reuse or change them.

Instead, define the trust decision outside the query where the platform can enforce it. Separate privileged and untrusted workflows, restrict runner groups to selected repositories, use environments for sensitive deployments, minimize token permissions, and avoid exposing persistent self-hosted runners to untrusted pull-request code.

Custom queries should detect dangerous data flow or workflow structure, while repository and runner policies enforce who can execute code on privileged infrastructure. Treating a query heuristic as the only runner boundary creates a control that looks precise but rests on unreliable identity.

Retest merge queue workflows

CodeQL now recognizes github.event.merge_group as untrusted data for workflows triggered by merge_group. That matters when a repository uses GitHub merge queues and interpolates event data into shell commands, environment variables, output files, cache keys, or artifact names.

Review expressions near run: steps:

- name: Unsafe example
  run: echo "${{ github.event.merge_group.head_ref }}"

The safer pattern is to pass the value through an environment variable and quote it inside the shell. This does not make every operation safe, but it prevents the expression from being inserted directly into generated shell source.

- name: Safer handling
  env:
    HEAD_REF: ${{ github.event.merge_group.head_ref }}
  run: printf '%s\n' "$HEAD_REF"

Then ask what the value controls. A quoted value used only for logging has a different risk from one used as a path, command, package name, or deployment target.

Recheck cache-poisoning alerts

Three cache-poisoning queries now account for read-only cache access on low-trust triggers in the default branch scope. CodeQL keeps results only for triggers GitHub allows to write into that cache scope. This should improve accuracy, but it can also change an existing alert baseline.

Do not dismiss all disappearing cache alerts as “fixed by the tool.” Confirm that low-trust jobs really have read-only access, that no alternate cache or artifact store remains writable, and that privileged jobs do not execute files restored from an untrusted key.

Use explicit permissions and separate cache namespaces where trust differs:

permissions:
  contents: read

- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

Pin third-party Actions to full commit SHAs for sensitive workflows. A careful cache key cannot protect a workflow that executes compromised Action code with a powerful token.

Expect different JavaScript and TypeScript findings

CodeQL 2.26.3 adds source modeling and framework knowledge that can reveal paths older scans missed:

  • custom models can identify a file through file:<path> and model its public exports;
  • Vue Composition API helpers such as ref, reactive, and computed have flow models;
  • Vue Router’s useRoute() values are treated as client-side remote sources;
  • declared Sails Action2 inputs are treated as remote sources;
  • promise-wrapped HTTP response data flows into fulfillment values;
  • @fastify/rate-limit is recognized by the missing-rate-limiting query.

For a Vue application, this means route.query, route.params, route.path, route.fullPath, and route.hash can participate in data-flow results. Review how these values reach DOM operations, URLs, storage, analytics, or backend requests. The presence of a route value is not itself a vulnerability; the source-to-sink path and sanitization determine whether the alert is useful.

For a Fastify API, the new rate-limiter recognition may remove a false positive when @fastify/rate-limit is correctly registered. Confirm registration scope and configuration before dismissing the alert. A plugin installed in package.json but registered only on one route does not protect the entire service.

Compare alerts without losing history

Export or record the open-alert baseline before the engine update. After scanning with 2.26.3, group differences into four categories:

Change What to verify
New alert New source/sink model, source-code change, or query update
Missing alert False-positive fix, model change, or accidental loss of coverage
Changed path Whether the shorter path still represents the same vulnerability
Query failure Removed API, incompatible query pack, or compilation error

Review a sample manually. Alert count alone is a weak success metric: ten accurate alerts can be more useful than one hundred noisy ones, but zero alerts can also mean the scan did not build the application correctly.

In a Node.js or fintech service, prioritize paths that reach payment mutation, account authorization, secret access, deployment credentials, cache writes, or persistent self-hosted runners. Attach the reviewed code path and decision to the alert so a future engineer can understand why it was fixed or dismissed.

Roll out custom packs through a canary repository

Compile custom packs against the new CodeQL release before organization-wide use. Run one representative JavaScript/TypeScript repository containing framework code and GitHub Actions workflows. Keep the previous successful scan available for comparison.

Your canary should prove:

  • the database builds successfully;
  • every intended query suite executes;
  • custom packs compile without removed APIs;
  • workflow analysis includes merge_group where used;
  • new framework alerts have understandable paths;
  • alert uploads retain the expected category and history;
  • scan duration and memory remain acceptable.

Only then expand to additional repositories. If a custom query fails, fix the query pack rather than disabling the entire security suite. If new modeling creates noisy results, narrow custom models or triage findings with evidence instead of broadly excluding framework directories.

Primary references

CodeQL 2.26.3 should improve signal quality, but automatic deployment does not remove the need for engineering review. Search for the removed module, test custom packs, inspect new framework paths, and verify workflow trust boundaries independently of runner-label heuristics.