Study guide

14.3 CodeQL SAST in Pipelines and Containers

Microsoft Certified: Azure DevOps Engineer Expert AZ-400

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Flow of Work, Traceability & Work Tracking

1.1 Flow of Work, GitHub Flow & Feedback Cycles 1.2 Work Tracking with Azure Boards & GitHub Projects 1.3 End-to-End DevOps Traceability & Quality Tracking

2 Chapter 2: DevOps Metrics, Dashboards & Team Collaboration

2.1 DORA Metrics, Flow Metrics & Dashboard Design 2.2 Lifecycle Metrics Across the Six DevOps Phases 2.3 Work Item Queries, WIQL Charts & Analytics 2.4 Project Documentation: Wikis, Mermaid Diagrams & Release Notes 2.5 Webhooks, Service Hooks & Microsoft Teams ChatOps

3 Chapter 3: Git Branching Strategies & Pull Request Workflows

3.1 Git Branching Models & Strategy Design 3.2 Pull Request Workflows & Merge Strategies 3.3 Branch Policies, Quality Gates & Compliance Restrictions

4 Chapter 4: Repository Management, Optimization & Git Data Operations

4.1 Git LFS Architecture & .gitattributes Tracking 4.2 LFS History Migration, git-fat & File Locking 4.3 Git Repository Scaling, Scalar & Monorepo Governance 4.4 Repository Permissions & Git Tag Governance 4.5 Git Data Recovery & Sensitive-Data Scrubbing

5 Chapter 5: Package Management & Dependency Versioning

5.1 Selecting Package Tools: Azure Artifacts vs. GitHub Packages 5.2 Feed Scoping, Upstream Sources & Pipeline Authentication 5.3 Package Views, Immutability & Quality Promotion 5.4 Dependency Versioning: SemVer, CalVer & Automated Versioning 5.5 Pipeline Artifact Versioning & Artifact Storage Strategy

6 Chapter 6: Pipeline Infrastructure, Agents & Integration

6.1 Selecting a CI/CD Solution: Azure Pipelines vs. GitHub Actions 6.2 GitHub-Azure Pipelines Integration & Hybrid Migration 6.3 Hosted vs. Self-Hosted Agents & Runners 6.4 VMSS Elastic Pools, Container Jobs & Agent Governance 6.5 Pipeline Triggers, Filters & Concurrency Management

7 Chapter 7: YAML Pipeline Architecture & Reusable Elements

7.1 YAML Pipeline Anatomy: Stages, Jobs, Steps & Workspaces 7.2 Job Execution Order: DAG Dependencies, Parallelism & Conditions 7.3 Reusable Elements: Templates, Parameters & Variables 7.4 Variable Groups, Secret Variables & Key Vault Linking 7.5 YAML Environments, Checks & Deployment Approvals

8 Chapter 8: Testing Strategy, Quality Gates & Code Coverage

8.1 Test Strategy Design: Local, Unit & Integration Testing 8.2 Load, Stress & Performance Testing in Pipelines 8.3 Test Execution Tasks, Agents & Results Integration 8.4 Code Coverage Analysis & SonarQube Integration 8.5 Quality Gates, Release Gates & Governance Checks

9 Chapter 9: Modern Deployment Strategies & Zero-Downtime Delivery

9.1 Progressive Delivery: Blue-Green, Canary & Ring Deployments 9.2 Minimizing Downtime: Deployment Slots & Rolling Updates 9.3 Feature Flags with Azure App Configuration & Feature Manager 9.4 Designing the High-Priority Hotfix Path 9.5 Ordered Dependency Deployments, Resiliency & Rollback

10 Chapter 10: Artifact Deployment & Database DevOps

10.1 Containerized Application Delivery: ACR, AKS & Container Apps 10.2 Binary, Web App, Function & Scripted Deployments 10.3 Database DevOps: State-Based & Migration-Based Strategies

11 Chapter 11: Infrastructure as Code (IaC) & Azure Deployment Environments

11.1 Infrastructure as Code Strategy: Bicep, ARM & Terraform 11.2 Desired State Configuration & Azure Machine Configuration 11.3 Azure Deployment Environments (ADE) & Developer Self-Service

12 Chapter 12: Pipeline Maintenance, Health & Modernization

12.1 Pipeline Health, Flaky Tests & Reliability Engineering 12.2 Pipeline Optimization: Caching, Slicing & Concurrency 12.3 Artifact & Build Retention Governance 12.4 Modernizing CI/CD: Classic to YAML Migration

13 Chapter 13: Authentication, Authorization & Identity Governance

13.1 Microsoft Entra Service Principals & Managed Identities 13.2 Service Connections, Workload Identity & Personal Access Tokens 13.3 Azure DevOps Projects, Teams & Permission Evaluation 13.4 Access Levels, GitHub Roles & Outside Collaborators

14 Chapter 14: Secrets Management, Sensitive Data & DevSecOps Scanning

14.1 Azure Key Vault, Secret Variables & Secretless CI/CD 14.2 Security Scanning Strategy, GHAS & Secret Scanning 14.3 CodeQL SAST in Pipelines and Containers 14.4 Software Supply Chain, Container Scanning & Cloud Defender

15 Chapter 15: Telemetry Collection, Azure Monitor & Alerting

15.1 Azure Monitor Architecture, AMA & Data Collection Rules 15.2 Application Insights & Specialized Azure Monitor Insights 15.3 Alerting Rules, Action Groups & GitHub Repository Insights

16 Chapter 16: Telemetry Analysis, Distributed Tracing & SRE Practices

16.1 Distributed Tracing, Application Map & Exception Triage 16.2 KQL Log Analytics, SRE Observability & Error Budgets

14.3 CodeQL SAST in Pipelines and Containers

Key Takeaways Explain This Topic AI

CodeQL extracts a relational database during compilation and then runs queries over it, which is why a build that performs no compilation yields an empty database.

Taint tracking follows untrusted data from a source through sanitizers to a sink, detecting injection, path traversal and deserialisation flaws.

In Azure Pipelines the sequence is AdvancedSecurity-Codeql-Init, the build, then AdvancedSecurity-Codeql-Analyze; in GitHub Actions it is codeql-action/init, the build, then codeql-action/analyze.

Analysing a containerised build requires setting container on the job so the extractor observes the same toolchain, and a full SDK image because the extractor needs glibc.

SARIF is the interchange format that lets third-party scanners publish into the same code scanning dashboard as CodeQL.

Last updated: September 2026

14.3 CodeQL SAST in Pipelines and Containers

Secret scanning finds credentials that are already text. Finding an exploitable code path requires semantic analysis of a compiled program, which is what CodeQL does - and why a containerized build forces the analysis into the same container.

1. CodeQL: Semantic Static Application Security Testing (SAST)

Traditional static code analyzers rely on simple syntax tree parsing or regular expression pattern matching. These tools generate overwhelming numbers of false positives and fail to trace complex data flows across multiple classes, methods, and files.

CodeQL is Microsoft and GitHub's industry-leading semantic code analysis engine. CodeQL treats code as data . ┌──────────────────────┐ ┌─────────────────────────┐ ┌───────────────────────┐

  • │ Source Code Files │ ───► │ CodeQL Extractor │ ───► │ CodeQL Database │
  • │ (C#, Java, TS, Py) │ │ (Monitors Compilers/AST)│ │ (Relational DB Schema)│
  • └──────────────────────┘ └─────────────────────────┘ └───────────┬───────────┘
  • │
  • ▼
  • ┌──────────────────────┐ ┌─────────────────────────┐ ┌───────────────────────┐
  • │ SARIF / Alerts Tab │ ◄─── │ CodeQL Taint Queries │ ◄─── │ Open-Source CodeQL │
  • │ (Pull Request Gates) │ │ (Source ──► Sink Paths) │ │ Query Packs (GitHub) │
  • └──────────────────────┘ └─────────────────────────┘ └───────────────────────┘
  • How CodeQL Works: The Extraction Phase

Extraction : During the build process, CodeQL extracts the codebase into a relational database capturing abstract syntax trees (AST), control flow graphs (CFG), data flow graphs, and lexical tokens.

Interpreted Languages (JavaScript/TypeScript, Python, Ruby): Extracted directly from raw source files without compilation.

Compiled Languages (C/C++, C#, Java/Kotlin, Go, Swift): Requires an active build step ( dotnet build , mvn compile , make ). CodeQL hooks into the compiler process to extract code structure as it compiles.

Database Generation : A queryable relational snapshot of the codebase is saved on the build agent.

Query Execution : CodeQL runs a suite of declarative queries written in the object-oriented QL language against the database.

Taint Tracking: Sources, Sanitizers, and Sinks

The core strength of CodeQL is taint tracking analysis (tracking data flow from untrusted inputs to dangerous execution points):

Source : Where untrusted data enters the application (e.g., HTTP request body, query parameters, headers, URL route parameters).

Sanitizer / Guard : Code logic that validates, escapes, or sanitizes the data (e.g., parameterized SQL queries, HTML entity encoders, regex validators).

Sink : A dangerous execution function where unvalidated data causes security exploits (e.g., SqlCommand.CommandText , eval() , Process.Start() , Response.Write() ).

If untrusted data flows from a Source to a Sink without passing through a recognized Sanitizer , CodeQL flags a vulnerability path with cryptographic certainty.

Key Vulnerability Classes Detected by CodeQL

SQL Injection (CWE-89) : Untrusted strings concatenated directly into database query commands.

Cross-Site Scripting / XSS (CWE-79) : Unsanitized user inputs reflected back into browser DOM responses.

Command Injection (CWE-78) : User input passed directly to operating system shell processes ( bash -c , cmd.exe ).

Path Traversal (CWE-22) : Manipulated file paths ( ../../etc/passwd ) accessing unauthorized file system directories.

Insecure Deserialization (CWE-502) : Deserializing untrusted object streams into runtime memory.

2. Implementing CodeQL in CI/CD Pipelines

Candidates must know how to configure CodeQL scanning in both GitHub Actions and Azure Pipelines .

Pattern A: GitHub Actions Workflow ( github/codeql-action )

In GitHub, CodeQL is executed using the official github/codeql-action action suite: # .github/workflows/codeql-analysis.yml

name: 'CodeQL Security Scanning'

on:

push:

branches: [ 'main' ]

pull_request:

branches: [ 'main' ]

schedule:

- cron: '30 1 * * 1' # Weekly scheduled baseline scan

jobs:

analyze:

  • name: Analyze Codebase
  • runs-on: 'ubuntu-latest'

permissions:

  • actions: read
  • contents: read
  • security-events: write # Required to upload SARIF results to Security tab

strategy:

fail-fast: false

matrix:

language: [ 'csharp', 'javascript-typescript' ]

steps:

  • name: Checkout repository
  • uses: actions/checkout@v4
  • # 1. Initialize CodeQL database for target languages
  • name: Initialize CodeQL
  • uses: github/codeql-action/init@v3

with:

  • languages: ${{ matrix.language }}
  • queries: security-extended # Ingests standard + aggressive security queries
  • # 2. Build compiled languages (Required for C#, Java, C++, Go)
  • name: Build C# Solution
  • if: matrix.language == 'csharp'
  • run: |
  • dotnet restore ContosoApp.sln
  • dotnet build ContosoApp.sln --configuration Release --no-incremental
  • # 3. Perform CodeQL Analysis
  • name: Perform CodeQL Analysis
  • uses: github/codeql-action/analyze@v3

with:

  • category: "/language:${{ matrix.language }}"
  • Pattern B: Azure Pipelines Workflow ( AdvancedSecurity-* Tasks)

When using GitHub Advanced Security for Azure DevOps, Microsoft provides dedicated pipeline tasks: # azure-pipelines.yml: Advanced Security in Azure Pipelines

trigger:

- main

pr:

- main

pool:

vmImage: 'windows-latest'

steps:

  • checkout: self
  • fetchDepth: 0 # Deep clone ensures accurate git blame & commit tracking
  • # 1. Initialize CodeQL environment
  • task: AdvancedSecurity-Codeql-Init@1
  • displayName: 'Initialize CodeQL Analysis Engine'

inputs:

  • languages: 'csharp'
  • querysuite: 'security-extended'
  • # 2. Compile application (CRITICAL: Must occur between Init and Analyze!)
  • task: DotNetCoreCLI@2
  • displayName: 'Compile C# Application'

inputs:

  • command: 'build'
  • projects: '**/*.csproj'
  • arguments: '--configuration Release'
  • # 3. Analyze CodeQL Database
  • task: AdvancedSecurity-Codeql-Analyze@1
  • displayName: 'Execute CodeQL Taint Analysis'
  • # 4. Consolidate and Publish Alerts
  • task: AdvancedSecurity-Publish@1
  • displayName: 'Publish Security Alerts to Azure DevOps Repos'
  • condition: succeededOrFailed()

Important

Top AZ-400 Exam Concept: The Compiled Language Build Rule A major exam trap involves pipelines that initialize CodeQL ( AdvancedSecurity-Codeql-Init@1 ) and immediately execute analysis ( AdvancedSecurity-Codeql-Analyze@1 ) without compiling the code . For compiled languages (C#, C++, Java, Go), if the code is not compiled between the Init and Analyze tasks, the CodeQL database remains empty. The scan will complete with zero findings even if the code contains blatant vulnerabilities!

3. SARIF and Centralized Security Dashboards

SARIF (Static Analysis Results Interchange Format) is an open OASIS standard JSON-based format for exchanging static analysis results between security scanning tools and engineering platforms.

SARIF Architecture and Integration

Both CodeQL in GitHub Actions and Advanced Security in Azure Pipelines output results natively as .sarif files.

Third-party SAST tools (such as SonarQube, Checkmarx, Snyk, and Veracode) can export findings to SARIF.

Using the github/codeql-action/upload-sarif action or Azure Pipelines SARIF upload tasks, third-party scanner findings are uploaded directly into GitHub Security or Azure DevOps Advanced Security dashboards.

Developers view annotations directly within Pull Request code diffs, preventing PR merges when security policies fail.

SAST vs. DAST vs. IAST vs. SCA Comparison Matrix

Security Discipline Tool Example Pipeline Phase Input Analyzed Typical Vulnerabilities Detected

SAST (Static Application Security Testing) CodeQL, SonarQube PR Validation / CI Build Source code / Abstract Syntax Trees SQLi, XSS, Buffer Overflows, Path Traversal

Secret Scanning GHAS Secret Scanning, Gitleaks Pre-commit / Push / CI Git commits / Text strings Hardcoded passwords, Azure keys, AWS secrets, PATs

SCA (Software Composition Analysis) Dependabot, Snyk, Black Duck PR Validation / Scheduled Package manifests ( package.json , pom.xml ) Known CVEs in open-source dependencies, license compliance

DAST (Dynamic Application Security Testing) OWASP ZAP, Burp Suite Post-Deploy / Staging Gate Running HTTP web endpoints Broken authentication, CORS misconfigurations, server headers

IAST (Interactive Application Security Testing) Contrast Security Integration Testing Runtime bytecode + agent telemetry Real-time code execution flaws during test automation

4. Running CodeQL Analysis in a Container

CodeQL builds its database by observing a real build , so a project that only compiles inside a container must run the analysis inside that same container. Otherwise the autobuild step fails, or worse, silently produces an empty database and a green "no alerts" result.

GitHub Actions. Set container: on the job. Every step - including the CodeQL init, build and analyze steps - then executes inside that image, so the extractor traces the same compiler and toolchain the product uses: jobs:

analyze:

runs-on: ubuntu-latest

container:

image: mcr.microsoft.com/dotnet/sdk:9.0

permissions:

  • security-events: write
  • contents: read

steps:

  • uses: actions/checkout@v4
  • uses: github/codeql-action/init@v3

with:

  • languages: csharp
  • build-mode: manual
  • run: dotnet build --no-incremental
  • uses: github/codeql-action/analyze@v3

Three constraints decide whether the container job works:

The image must contain the build toolchain and a compatible glibc. CodeQL's extractor binaries are dynamically linked; minimal images such as alpine (musl libc) or distroless images cannot host the extractor. Use a full SDK image for analysis and keep the small image for the runtime stage.

--no-incremental (or the language equivalent) is mandatory. A cached or up-to-date build performs no compilation, the extractor sees no source, and the resulting database is empty.

security-events: write must be granted , otherwise the analyze step cannot upload the SARIF results to code scanning.

  • Azure Pipelines. The equivalent is a container job wrapping the Advanced Security tasks: - job: codeql
  • container: mcr.microsoft.com/dotnet/sdk:9.0

steps:

  • task: AdvancedSecurity-Codeql-Init@1
  • inputs: { languages: 'csharp' }
  • script: dotnet build --no-incremental
  • task: AdvancedSecurity-Codeql-Analyze@1

Note the distinction the exam likes to test: running CodeQL in a container analyses the source code that is built inside that image, whereas container image scanning (Defender for Containers, ACR scanning) inspects the published image layers for vulnerable OS and library packages. They answer different questions and neither replaces the other.

  • 5. Realistic Exam Scenario & Common Traps
  • Scenario: Global FinTech Payment Gateway Pipeline

Organization : Contoso Payments develops an enterprise payment gateway in C# .NET 8 and React hosted in Azure Repos. Developers frequently interact with Stripe API keys and Azure Cosmos DB master keys.

DevOps Strategy Implemented :

Pre-Receive Defense : The security team enables GHAS for Azure DevOps across all payment repositories and turns on Push Protection . A junior developer attempts to push code containing a live Azure Cosmos DB primary connection string; the git push is blocked instantly at the CLI with an explanatory rejection message.

Pull Request Security Gate : A PR validation pipeline runs AdvancedSecurity-Codeql-Init@1 , compiles the solution with DotNetCoreCLI@2 , and runs AdvancedSecurity-Codeql-Analyze@1 using the security-extended query suite.

SARIF Pull Request Annotation : A developer introduces a raw SQL query concatenation ( SELECT * FROM Accounts WHERE Id = '" + id + "' ). CodeQL detects the taint flow from the API controller to the database query and automatically flags the exact line in the PR review window, blocking the PR merge branch policy until the query is refactored to use parameterized commands.

Common Exam Traps to Avoid

Trap: Believing Secret Scanning Push Protection can be bypassed silently. Developers can only bypass push protection if the organization permits it, and every bypass requires choosing a specific justification (false positive, test secret) which is immediately recorded in the security audit log.

Trap: Assuming CodeQL executes the application binary. CodeQL is strictly a static analysis tool. It analyzes the structure, flow, and semantics of the code; it does not launch web servers or execute HTTP requests (which is the domain of DAST tools like OWASP ZAP).

Trap: Forgetting the security-events: write permission in GitHub Actions. When authoring custom GitHub Actions workflows that execute CodeQL or upload SARIF files, omitting security-events: write from the workflow job permissions causes the SARIF upload to fail with an HTTP 403 Forbidden error.

Loading diagram... CodeQL Semantic Taint Analysis and CI/CD Pull Request Quality Gate