Security

GitHub Security: Dependabot, CodeQL & Secret Scanning — Complete Guide 2026

Software supply chain attacks surged 742% between 2019 and 2025 (Sonatype State of the Software Supply Chain). Your repository is not just source code — it is an attack surface. GitHub's integrated security features, from Dependabot to CodeQL to secret scanning, provide a layered defence-in-depth strategy that catches vulnerabilities before they reach production.

Md Sanwar Hossain April 8, 2026 24 min read GitHub Security
GitHub security layers: Dependabot, CodeQL, secret scanning, branch protection, SLSA

TL;DR — Minimum Viable GitHub Security Posture

"Enable these five controls today: Dependabot security alerts + version updates to patch vulnerable dependencies automatically. CodeQL default setup for SAST on every PR. Secret scanning with push protection to block credentials before they are committed. Branch protection on main requiring PR reviews. CODEOWNERS for mandatory review by domain experts. These five controls stop the majority of real-world supply chain attacks."

Table of Contents

  1. Software Supply Chain: The Threat Model
  2. Dependabot: Automated Dependency Security
  3. CodeQL: Static Application Security Testing (SAST)
  4. Secret Scanning and Push Protection
  5. Branch Protection Rules: Governance at Scale
  6. CODEOWNERS: Mandatory Domain Expert Review
  7. Signed Commits and Tags: Commit Identity Verification
  8. SLSA: Supply Chain Levels for Software Artifacts
  9. GitHub Advanced Security: Enterprise Features
  10. Complete GitHub Security Hardening Checklist

1. Software Supply Chain: The Threat Model

Modern applications depend on hundreds or thousands of open-source packages. The average Java application has 150+ direct and transitive dependencies. Each dependency is a potential attack vector — vulnerable, malicious, or both. The supply chain attack surface includes:

GitHub's integrated security features address each of these attack vectors. Understanding the threat model helps you prioritise which controls to enable first.

2. Dependabot: Automated Dependency Security

Dependabot is GitHub's automated dependency update service. It has two distinct modes that are often confused:

Dependabot Configuration Reference

# .github/dependabot.yml
version: 2
updates:
  # Maven (Java) dependencies:
  - package-ecosystem: "maven"
    directory: "/"
    schedule:
      interval: "weekly"
      day: "monday"
      time: "09:00"
      timezone: "Asia/Dhaka"
    # Limit PR count to avoid overwhelming the team:
    open-pull-requests-limit: 5
    # Group minor/patch updates into a single PR:
    groups:
      spring-framework:
        patterns: ["org.springframework*"]
      aws-sdk:
        patterns: ["software.amazon.awssdk*"]
    # Require review from CODEOWNERS:
    reviewers:
      - "platform-team"
    labels:
      - "dependencies"
      - "automated"
    commit-message:
      prefix: "chore(deps)"
      include: "scope"
    # Ignore major version upgrades for stable deps:
    ignore:
      - dependency-name: "org.springframework*"
        update-types: ["version-update:semver-major"]

  # npm (Node/frontend):
  - package-ecosystem: "npm"
    directory: "/frontend"
    schedule:
      interval: "weekly"
    groups:
      react-ecosystem:
        patterns: ["react", "react-*", "@types/react*"]

  # GitHub Actions:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    # Auto-merge patch/minor updates (safe for actions):
    open-pull-requests-limit: 10

Auto-Merging Safe Dependabot PRs

# .github/workflows/dependabot-auto-merge.yml
on:
  pull_request:

permissions:
  contents: write
  pull-requests: write

jobs:
  auto-merge:
    runs-on: ubuntu-latest
    if: github.actor == 'dependabot[bot]'
    steps:
      - name: Fetch Dependabot metadata
        id: meta
        uses: dependabot/fetch-metadata@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}

      # Auto-merge patch and minor updates:
      - name: Approve and merge safe updates
        if: |
          steps.meta.outputs.update-type == 'version-update:semver-patch' ||
          steps.meta.outputs.update-type == 'version-update:semver-minor'
        run: gh pr review --approve "$PR_URL" && gh pr merge --auto --squash "$PR_URL"
        env:
          PR_URL: ${{ github.event.pull_request.html_url }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GitHub security: Dependabot, CodeQL, secret scanning, branch protection, SLSA supply chain
GitHub's layered security model: dependency scanning, SAST, secret protection, access control, and supply chain integrity. Source: mdsanwarhossain.me

3. CodeQL: Static Application Security Testing (SAST)

CodeQL is GitHub's semantic code analysis engine. Unlike pattern-matching linters, CodeQL builds a relational database of your code's abstract syntax tree and data flows, then runs queries against it. This enables it to detect complex vulnerabilities like SQL injection across multiple function calls, XSS through indirect data paths, and insecure cryptographic API misuse — things simple regex-based tools miss entirely.

Enabling CodeQL: Default vs Advanced Setup

# Method 1: Default setup (easiest, recommended for most teams)
# Enable via: Security tab → Code scanning → Set up code scanning
# GitHub automatically detects language and runs default queries.
# Results appear as PR annotations and in Security → Code scanning alerts.

# Method 2: Advanced setup for customisation:
# .github/workflows/codeql.yml

name: "CodeQL Security Analysis"
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  schedule:
    - cron: "30 2 * * 1"  # Weekly scan at 2:30 AM Monday

jobs:
  analyze:
    name: Analyze (${{ matrix.language }})
    runs-on: ubuntu-latest
    permissions:
      security-events: write   # required for uploading results
      actions: read
      contents: read
    strategy:
      fail-fast: false
      matrix:
        language: [java-kotlin, javascript-typescript]
    steps:
      - uses: actions/checkout@v4
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
          # Use extended query suite (includes more security checks):
          queries: security-extended
          # Add custom queries:
          config: |
            query-filters:
              - exclude:
                  id: java/tainted-path   # suppress if you have mitigations
      
      # For Java: build the project so CodeQL can analyze compiled code
      - uses: actions/setup-java@v4
        with:
          java-version: "21"
          distribution: temurin
          cache: maven
      - run: mvn compile -DskipTests
      
      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3
        with:
          category: "/language:${{ matrix.language }}"

Key CodeQL Vulnerability Categories for Java

Vulnerability CodeQL Query Example
SQL Injection java/sql-injection User input directly in SQL string
Path Traversal java/path-injection ../../etc/passwd via file API
SSRF java/ssrf User-controlled URL in HTTP client
Deserialization java/unsafe-deserialization ObjectInputStream with untrusted data
Weak Cryptography java/weak-cryptographic-algorithm MD5, SHA-1, DES usage
Log Injection java/log-injection User input in log statements (Log4Shell pattern)

4. Secret Scanning and Push Protection

Secret scanning detects credentials, API keys, tokens, and other sensitive strings committed to your repository. GitHub partners with 100+ service providers (AWS, Azure, GCP, Stripe, Twilio, Slack, etc.) to identify valid tokens and alert both you and the provider automatically — enabling token revocation within minutes of a leak.

Push Protection: The Most Important Feature

Regular secret scanning alerts you after a secret is committed and potentially accessible in history. Push protection (GitHub Advanced Security) blocks the push before the commit enters the repository — preventing the secret from ever reaching a public or internal system. This is the gold standard for credential protection.

# Push protection workflow (what happens when a developer pushes a secret):
$ git push origin feature/payment
remote: GH013: Repository rule violations found for refs/heads/feature/payment.
remote: Review the following errors before continuing:
remote:
remote: — Commits will be blocked by GitHub because they contain a potential secret.
remote:   — Push cannot contain secrets
remote:     Location: src/config/application.properties
remote:     Secret: AWS Access Key ID (AKIAIOSFODNN7EXAMPLE)
remote:
remote: To push despite this block, navigate to:
remote:   https://github.com/org/repo/security/secret-scanning/unblock

# The developer must either:
# 1. Remove the secret, use an environment variable, and recommit
# 2. Navigate to GitHub UI to justify bypassing (logged for audit)

# Correct approach: Use environment variables, never hardcode:
# BAD:
aws.accessKeyId=AKIAIOSFODNN7EXAMPLE

# GOOD (application.properties):
aws.accessKeyId=${AWS_ACCESS_KEY_ID}
# Set via: GitHub Actions secret → OIDC → no static key needed at all!

Custom Secret Patterns

# Define custom patterns for org-specific secrets in Security settings
# Example: internal service tokens starting with "myco_sk_":
# Pattern: myco_sk_[A-Za-z0-9]{32}
# Test string: myco_sk_AbCdEfGhIjKlMnOpQrStUvWxYz012345

# Custom patterns can be added per-repo or org-wide
# They appear in push protection and historical scanning alerts

# GitHub API: list secret scanning alerts programmatically:
$ gh api repos/org/repo/secret-scanning/alerts --jq '.[].secret_type'

5. Branch Protection Rules: Governance at Scale

Branch protection rules prevent direct pushes to critical branches and enforce quality gates before merging. Configure via Settings → Branches → Add rule. For organisations, use the newer Repository Rulesets (available since 2023) which can be inherited across repositories and have better bypass control.

Rule Purpose Recommended Setting
Require pull request reviews No direct pushes; all changes reviewed Min 1-2 reviewers; dismiss stale on push
Require status checks CI must pass before merge Require all CI jobs; require branch up-to-date
Require conversation resolution All review comments addressed before merge Enabled for main; optional for dev branches
Require signed commits GPG/SSH-signed commits only Enable for regulated/compliance repos
Restrict force pushes Prevent history rewriting Always enable on main/release branches
Restrict deletions Prevent accidental branch deletion Always enable on main/release branches

6. CODEOWNERS: Mandatory Domain Expert Review

The CODEOWNERS file defines who must approve changes to specific files or directories. When combined with branch protection's "Require review from Code Owners" setting, changes to sensitive areas (auth, payment, infra) require sign-off from domain experts — not just any reviewer.

# .github/CODEOWNERS
# Format: path pattern  owner(s)

# Global default: everything needs approval from platform-lead:
*                    @platform-lead

# Auth and security code — security team must review:
/src/auth/           @org/security-team
/src/security/       @org/security-team
/.github/workflows/  @org/security-team @org/platform-team

# Payment processing — payment team leads only:
/src/payment/        @payment-lead @cto

# Database migrations — data team and DBA:
/db/migrations/      @org/data-team

# Infrastructure as Code — SRE team:
/terraform/          @org/sre-team
/k8s/                @org/sre-team

# Shared library — library maintainers:
/libs/               @org/platform-team

# CI/CD configuration — DevOps team:
/.github/            @org/devops-team

# Documentation — anyone on the docs team:
/docs/               @org/docs-team

# Package files — platform team reviews dependency changes:
**/pom.xml           @org/platform-team
**/package.json      @org/platform-team

CODEOWNERS Best Practices

7. Signed Commits and Tags: Commit Identity Verification

Git allows setting any name and email address as the author of a commit — there is no built-in identity verification. Signed commits use GPG or SSH keys to cryptographically prove that a commit was made by a specific key holder. GitHub displays a green "Verified" badge for commits signed with a registered key.

# Option 1: GPG signing (traditional, works everywhere)
$ gpg --full-generate-key    # RSA 4096 or Ed25519 recommended
$ gpg --list-secret-keys --keyid-format=long
# Copy the key ID (after rsa4096/ or ed25519/)
$ git config --global user.signingkey KEYID
$ git config --global commit.gpgsign true
$ git config --global tag.gpgsign true

# Export public key to add to GitHub:
$ gpg --armor --export KEYID
# Paste in: Settings → SSH and GPG keys → New GPG key

# Option 2: SSH signing (simpler, GitHub supported since 2022)
$ git config --global gpg.format ssh
$ git config --global user.signingkey ~/.ssh/id_ed25519.pub
$ git config --global commit.gpgsign true
# Add the SSH key to GitHub: Settings → SSH and GPG keys → New SSH key (signing type)

# Verify a commit's signature:
$ git verify-commit HEAD
$ git log --show-signature -1

# Verify a tag signature:
$ git verify-tag v1.0.0

# Batch verify all commits on a branch:
$ git log --show-signature main | grep "^gpg:"

Requiring Signed Commits via Branch Protection

Enable "Require signed commits" in branch protection rules to block unverified commits from being merged into protected branches. Note: this also prevents merges using the GitHub UI unless the user has a registered signing key — requiring all team members to have GPG or SSH keys configured before enabling this rule.

8. SLSA: Supply Chain Levels for Software Artifacts

SLSA (Supply-chain Levels for Software Artifacts, pronounced "salsa") is an open security framework that defines integrity requirements for the software build process. It has four levels:

Level Name Requirements Threat Addressed
SLSA 1 Documented Build scripted; provenance generated Accidental mistakes
SLSA 2 Consistent Versioned; hosted build service; signed provenance Unauthorised code changes
SLSA 3 Verified Hardened build environment; two-party review Compromised build worker
SLSA 4 Assured Hermetic + reproducible builds; all deps SLSA 3+ Sophisticated insider attacks
# Generate SLSA provenance for a GitHub Actions build (SLSA 3):
# Uses: slsa-framework/slsa-github-generator

jobs:
  build:
    outputs:
      hashes: ${{ steps.hash.outputs.hashes }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: mvn package -DskipTests
      - name: Generate artifact hash
        id: hash
        run: |
          HASH=$(sha256sum target/app.jar | base64 -w0)
          echo "hashes=$HASH" >> $GITHUB_OUTPUT

  provenance:
    needs: [build]
    permissions:
      actions: read
      id-token: write   # OIDC for signing provenance
      contents: write   # upload to release
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
    with:
      base64-subjects: "${{ needs.build.outputs.hashes }}"
      upload-assets: true  # attach .intoto.jsonl to GitHub release

9. GitHub Advanced Security: Enterprise Features

GitHub Advanced Security (GHAS) unlocks additional features for private repositories on Teams/Enterprise plans. Public repositories get all GHAS features for free. Key GHAS-exclusive features:

Secret Scanning + Push Protection

Push protection blocks commits containing known credential patterns before they ever enter the repo. Covers 200+ token types from 100+ service providers. Enterprise customers get custom pattern support.

Code Scanning (CodeQL)

SAST on every PR. Results annotated directly on diff lines. Custom CodeQL queries for org-specific security rules. AI-powered autofix suggestions (Copilot Autofix) for detected vulnerabilities.

Dependency Review

PR-level dependency review shows new vulnerabilities introduced by dependency changes before merge. Action available for CI enforcement with fail thresholds by severity.

Security Overview Dashboard

Org-level dashboard aggregating security alerts across all repositories. Filter by severity, ecosystem, alert type. Enables security teams to prioritise remediation at scale.

10. Complete GitHub Security Hardening Checklist

Repository Level

Branch Protection (main/release branches)

GitHub Actions Security

Identity and Access

GitHub Security Dependabot CodeQL Secret Scanning SLSA Supply Chain Security

Leave a Comment

Related Posts

DevOps

GitHub Actions Advanced: Reusable Workflows & OIDC

Reusable workflows, composite actions, and OIDC keyless authentication for cloud deploys.

Software Dev

Advanced Git: Interactive Rebase, Cherry-Pick & Bisect

Master Git power-user commands for clean history, backporting fixes, and finding regressions.

Security

Zero Trust Microservices: mTLS, SPIFFE & SPIRE

Implement zero trust security with mutual TLS and workload identity in microservices.

Md Sanwar Hossain - Software Engineer
Md Sanwar Hossain

Software Engineer · Java · Spring Boot · Microservices · AI/LLM Systems

All Posts
Back to Blog
Last updated: April 8, 2026