GitHub Advanced Security: Configuration, Management, and Reporting Guide

READER BEWARE: THE FOLLOWING WRITTEN ENTIRELY BY AI WITHOUT HUMAN EDITING.

Introduction

GitHub Advanced Security (GHAS) represents GitHub’s comprehensive suite of security tools designed to help development teams identify and remediate security vulnerabilities before they reach production. Whether you’re managing a single repository or an entire enterprise, GHAS provides code scanning, secret scanning, and dependency review capabilities that integrate seamlessly into your development workflow.

This guide covers everything you need to know about GitHub Advanced Security: how to configure and enable its features, manage security policies across your organization, access reporting and analytics, and leverage GitHub’s built-in remediation workflows to efficiently address security findings.

What is GitHub Advanced Security?

GitHub Advanced Security is a collection of security features that help you find, prevent, and fix security vulnerabilities in your code. It includes:

  1. Code Scanning: Static analysis using CodeQL and third-party tools to find vulnerabilities in your codebase
  2. Secret Scanning: Detection of accidentally committed credentials, API keys, and other secrets
  3. Dependency Review: Analysis of pull requests to identify vulnerable dependencies before they’re merged
  4. Security Overview: Centralized dashboards for tracking security posture across repositories

Licensing and Availability

GitHub Advanced Security availability depends on your GitHub plan:

FeatureGitHub FreeGitHub ProGitHub TeamGitHub Enterprise
Code Scanning (Public Repos)
Code Scanning (Private Repos)✅ (GHAS license)
Secret Scanning (Public Repos)
Secret Scanning (Private Repos)✅ (GHAS license)
Secret Scanning Push Protection✅ (GHAS license)
Dependency Review
Security Overview

For public repositories, most features are available for free. For private repositories, you need GitHub Enterprise with a GitHub Advanced Security license.

Code Scanning with CodeQL

Code scanning is GitHub’s static analysis solution that identifies security vulnerabilities and coding errors in your code. The primary engine powering code scanning is CodeQL, GitHub’s semantic code analysis engine.

How CodeQL Works

CodeQL treats code as data, allowing you to write queries that search for specific patterns in your codebase. The process works in three stages:

  1. Database Creation: CodeQL builds a relational database representing your code structure
  2. Query Execution: Security queries run against the database to find vulnerabilities
  3. Alert Generation: Findings are surfaced as alerts in the Security tab

Enabling Code Scanning

GitHub provides a streamlined default setup that works for most repositories:

  1. Navigate to your repository on GitHub
  2. Click SettingsCode security and analysis
  3. Under Code scanning, click Set upDefault
  4. Review the configuration and click Enable CodeQL

The default setup:

  • Automatically detects supported languages
  • Runs on push events to the default branch
  • Runs on pull requests targeting the default branch
  • Uses the security-extended query suite

Method 2: Advanced Setup with Workflow File

For more control over code scanning, create a custom workflow:

# .github/workflows/codeql-analysis.yml
name: "CodeQL Analysis"

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]
  schedule:
    # Run weekly on Sunday at 4:00 AM UTC
    - cron: '0 4 * * 0'

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    timeout-minutes: 360
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: [ 'javascript', 'python', 'go' ]
        # Supported languages: cpp, csharp, go, java, javascript, python, ruby, swift

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Initialize CodeQL
      uses: github/codeql-action/init@v3
      with:
        languages: ${{ matrix.language }}
        # Override the default queries with a custom suite
        queries: security-extended,security-and-quality

    # For compiled languages (Java, C++, C#, Go, Swift), add build steps
    # Autobuild attempts to build any compiled language
    - name: Autobuild
      uses: github/codeql-action/autobuild@v3

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v3
      with:
        category: "/language:${{ matrix.language }}"

CodeQL Configuration Options

Query Suites

CodeQL provides several query suites with different coverage and false positive rates:

SuiteDescriptionUse Case
defaultCore security queries with low false positive rateProduction scanning
security-extendedExtended security queriesComprehensive security scanning
security-and-qualitySecurity + code quality queriesFull code analysis
- name: Initialize CodeQL
  uses: github/codeql-action/init@v3
  with:
    languages: javascript
    queries: security-extended

Custom Query Packs

You can use custom CodeQL query packs:

- name: Initialize CodeQL
  uses: github/codeql-action/init@v3
  with:
    languages: javascript
    packs: |
      codeql/javascript-queries:path/to/custom-queries
      my-org/my-security-queries@1.0.0      

Configuration File

Create a CodeQL configuration file for complex setups:

# .github/codeql/codeql-config.yml
name: "Custom CodeQL Config"

# Disable default queries and use custom ones
disable-default-queries: false

# Add custom query packs
packs:
  javascript:
    - codeql/javascript-queries

# Add custom queries from your repository
queries:
  - uses: ./custom-queries/javascript

# Exclude paths from analysis
paths-ignore:
  - '**/test/**'
  - '**/tests/**'
  - '**/node_modules/**'
  - '**/vendor/**'
  - '**/*.test.js'
  - '**/*.spec.js'

# Only analyze specific paths
paths:
  - src
  - lib

Reference the configuration file in your workflow:

- name: Initialize CodeQL
  uses: github/codeql-action/init@v3
  with:
    languages: javascript
    config-file: ./.github/codeql/codeql-config.yml

Viewing Code Scanning Results

Code scanning results appear in multiple locations:

  1. Security Tab: Navigate to SecurityCode scanning alerts
  2. Pull Request Checks: Results appear as check annotations on PRs
  3. API Access: Use the REST API or GraphQL to programmatically access alerts

Understanding Alert Severity

Alerts are classified by severity:

SeverityDescriptionAction Required
CriticalSevere vulnerabilities requiring immediate attentionImmediate fix required
HighSignificant security issuesFix in current sprint
MediumModerate security concernsFix when feasible
LowMinor issues or informationalConsider addressing
ErrorAnalysis errorsInvestigate configuration
WarningPotential issuesReview and assess
NoteInformational findingsOptional review

Managing Code Scanning Alerts

Alert States

Alerts can be in the following states:

  • Open: Active alert requiring attention
  • Closed: Resolved through code changes
  • Dismissed: Manually dismissed with a reason
  • Fixed: Automatically closed when vulnerable code is removed

Dismissing Alerts

When dismissing an alert, provide a reason:

  • False positive: The alert doesn’t represent a real vulnerability
  • Won’t fix: The vulnerability is accepted risk
  • Used in tests: The code is only used in test scenarios
# Using GitHub CLI to dismiss an alert
gh api repos/{owner}/{repo}/code-scanning/alerts/{alert_number} \
  -X PATCH \
  -f state=dismissed \
  -f dismissed_reason="false positive" \
  -f dismissed_comment="This pattern is safe in our context because..."

Code Scanning with Third-Party Tools

GitHub code scanning supports SARIF (Static Analysis Results Interchange Format) uploads from any tool:

# Example: Running ESLint and uploading results
- name: Run ESLint
  run: npx eslint . --format @microsoft/sarif --output-file eslint-results.sarif
  continue-on-error: true

- name: Upload ESLint SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: eslint-results.sarif
    category: eslint

Popular third-party integrations:

  • Semgrep: returntocorp/semgrep-action
  • Snyk: snyk/actions
  • SonarCloud: SonarSource analyzers
  • Checkmarx: Checkmarx GitHub Action

Secret Scanning

Secret scanning automatically detects secrets committed to your repository, including API keys, tokens, passwords, and other credentials.

How Secret Scanning Works

GitHub maintains partnerships with over 100 service providers to detect their specific token formats. When a secret is detected:

  1. Pattern Matching: GitHub scans code for known secret patterns
  2. Partner Notification: If enabled, the service provider is notified
  3. Alert Creation: An alert appears in the Security tab

Enabling Secret Scanning

Repository Level

  1. Navigate to SettingsCode security and analysis
  2. Under Secret scanning, click Enable
  3. Optionally enable Push protection

Organization Level

  1. Navigate to Organization SettingsCode security and analysis
  2. Enable secret scanning for all repositories:
    • All repositories
    • New repositories only
    • Public repositories only
# Using GitHub API to enable secret scanning
gh api orgs/{org}/repos/{repo} \
  -X PATCH \
  -f security_and_analysis.secret_scanning.status=enabled \
  -f security_and_analysis.secret_scanning_push_protection.status=enabled

Push Protection

Push protection prevents secrets from being pushed to GitHub in the first place:

# When push protection detects a secret, you'll see:
remote: error: GH013: Repository rule violations found for refs/heads/main.
remote: 
remote: - GITHUB_PUSH_PROTECTION: push protection detected a secret in commit abc1234
remote:   Secret type: GitHub Personal Access Token
remote:   Location: config/secrets.js:15
remote:
remote: To push, either remove the secret or use a bypass if you believe this is safe

Bypassing Push Protection

When push protection blocks a push, you have options:

  1. Remove the secret: The recommended approach
  2. Request bypass: For legitimate cases (requires admin approval)
  3. Allow bypass for specific patterns: Configure allowed patterns
# Configure custom patterns that are allowed
# In repository Settings → Code security → Secret scanning → Push protection

# Allowed patterns (example for test/mock tokens):
# - Pattern: test_[a-z0-9]{32}
# - Description: Test tokens for CI/CD

Custom Secret Patterns

Define custom patterns to detect organization-specific secrets:

  1. Navigate to Organization SettingsCode securitySecret scanning
  2. Click New pattern
  3. Define the pattern using regex:
# Example custom pattern for internal API keys
Name: Internal API Key
Pattern: INTERNAL_[A-Z0-9]{24}
Description: Detects internal API keys used in our services

Managing Secret Scanning Alerts

Alert Workflow

# List secret scanning alerts
gh api repos/{owner}/{repo}/secret-scanning/alerts

# Get specific alert details
gh api repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}

# Close an alert
gh api repos/{owner}/{repo}/secret-scanning/alerts/{alert_number} \
  -X PATCH \
  -f state=resolved \
  -f resolution=revoked

Resolution States

  • Open: Active alert requiring attention
  • Resolved - Revoked: Secret has been revoked/rotated
  • Resolved - False Positive: Detection was incorrect
  • Resolved - Used in Tests: Secret is only in test code
  • Resolved - Won’t Fix: Accepted risk

Secret Scanning Best Practices

  1. Enable Push Protection: Prevent secrets before they’re committed
  2. Rotate Immediately: When a secret is detected, rotate it immediately
  3. Use Environment Variables: Store secrets in environment variables, not code
  4. Configure .gitignore: Exclude sensitive file patterns
  5. Use Secret Managers: Integrate with HashiCorp Vault, AWS Secrets Manager, etc.

Dependency Review

Dependency review analyzes pull requests to identify changes to dependencies and highlight any that introduce vulnerabilities.

Enabling Dependency Review

Dependency review works automatically when:

  1. Dependency Graph is enabled
  2. Pull requests include changes to manifest files (package.json, Gemfile, requirements.txt, etc.)
# .github/workflows/dependency-review.yml
name: 'Dependency Review'
on: [pull_request]

permissions:
  contents: read

jobs:
  dependency-review:
    runs-on: ubuntu-latest
    steps:
      - name: 'Checkout Repository'
        uses: actions/checkout@v4
      
      - name: 'Dependency Review'
        uses: actions/dependency-review-action@v4
        with:
          # Fail on any vulnerability with severity >= high
          fail-on-severity: high
          
          # Also fail on these license types
          deny-licenses: GPL-3.0, AGPL-3.0
          
          # Allow specific packages with known issues
          allow-ghsas: GHSA-xxxx-xxxx-xxxx

Configuration Options

- name: 'Dependency Review'
  uses: actions/dependency-review-action@v4
  with:
    # Severity threshold: critical, high, moderate, low
    fail-on-severity: moderate
    
    # License checking
    allow-licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause
    deny-licenses: GPL-3.0, AGPL-3.0, LGPL-3.0
    
    # Scope filtering
    fail-on-scopes: runtime, development
    
    # Vulnerability filtering
    allow-ghsas: GHSA-xxxx-xxxx-xxxx, GHSA-yyyy-yyyy-yyyy
    
    # Output configuration
    comment-summary-in-pr: always

Understanding Dependency Review Results

When dependency review runs on a PR, it provides:

  1. Vulnerability Summary: New vulnerabilities introduced by the PR
  2. License Changes: Changes to dependency licenses
  3. Manifest Changes: Which files were modified

Results appear as:

  • Check run annotations
  • PR comments (if configured)
  • API-accessible data

Security Overview

Security Overview provides a centralized dashboard for managing security across your organization.

Accessing Security Overview

  1. Navigate to your organization
  2. Click Security tab
  3. Select from available views:
    • Overview: High-level security posture
    • Risk: Repositories by risk level
    • Coverage: Feature enablement status
    • CodeQL Pull Request Alerts: Recent PR findings

Dashboard Views

Overview Dashboard

The overview shows:

  • Total alerts by severity
  • Trend data over time
  • Top affected repositories
  • Recent activity

Risk View

Filter and sort repositories by:

  • Number of open alerts
  • Alert severity
  • Last activity date
  • Security feature coverage
Repository          | Critical | High | Medium | Low | Coverage
-------------------|----------|------|--------|-----|----------
api-service        | 2        | 5    | 12     | 8   | 100%
web-frontend       | 0        | 3    | 8      | 15  | 75%
internal-tools     | 1        | 2    | 4      | 3   | 50%

Coverage View

Track security feature adoption:

  • Code scanning enabled/disabled
  • Secret scanning enabled/disabled
  • Dependabot alerts enabled/disabled
  • Push protection enabled/disabled

Filtering and Exporting Data

# Export security overview data using GitHub API
gh api orgs/{org}/security-managers

# Get code scanning alerts across org
gh api orgs/{org}/code-scanning/alerts \
  --paginate \
  -q '.[] | [.repository.name, .state, .rule.severity, .rule.description] | @csv'

# Get secret scanning alerts across org
gh api orgs/{org}/secret-scanning/alerts \
  --paginate \
  -q '.[] | [.repository.name, .state, .secret_type] | @csv'

Reporting and Analytics

Accessing Security Reports

REST API Endpoints

# Code scanning alerts for a repository
GET /repos/{owner}/{repo}/code-scanning/alerts

# Code scanning alerts for an organization
GET /orgs/{org}/code-scanning/alerts

# Secret scanning alerts for a repository
GET /repos/{owner}/{repo}/secret-scanning/alerts

# Secret scanning alerts for an organization
GET /orgs/{org}/secret-scanning/alerts

# Dependabot alerts for a repository
GET /repos/{owner}/{repo}/dependabot/alerts

# Dependabot alerts for an organization
GET /orgs/{org}/dependabot/alerts

GraphQL Queries

# Query code scanning alerts
query {
  repository(owner: "owner", name: "repo") {
    vulnerabilityAlerts(first: 100) {
      nodes {
        createdAt
        dismissedAt
        securityVulnerability {
          severity
          package {
            name
          }
          advisory {
            summary
          }
        }
      }
    }
  }
}

Building Custom Reports

Python Script for Security Reporting

#!/usr/bin/env python3
"""
GitHub Advanced Security Reporting Script
Generates comprehensive security reports across repositories
"""

import os
import json
from datetime import datetime, timedelta
from github import Github
import csv

GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN')
ORG_NAME = "your-organization"

def get_code_scanning_alerts(g, org_name):
    """Fetch code scanning alerts across organization"""
    alerts = []
    org = g.get_organization(org_name)
    
    for repo in org.get_repos():
        try:
            repo_alerts = repo.get_codescan_alerts()
            for alert in repo_alerts:
                alerts.append({
                    'repository': repo.name,
                    'rule_id': alert.rule.id,
                    'rule_description': alert.rule.description,
                    'severity': alert.rule.severity,
                    'state': alert.state,
                    'created_at': alert.created_at.isoformat(),
                    'html_url': alert.html_url
                })
        except Exception as e:
            print(f"Could not fetch alerts for {repo.name}: {e}")
    
    return alerts

def get_secret_scanning_alerts(g, org_name):
    """Fetch secret scanning alerts across organization"""
    alerts = []
    org = g.get_organization(org_name)
    
    for repo in org.get_repos():
        try:
            repo_alerts = repo.get_secret_scanning_alerts()
            for alert in repo_alerts:
                alerts.append({
                    'repository': repo.name,
                    'secret_type': alert.secret_type,
                    'state': alert.state,
                    'created_at': alert.created_at.isoformat(),
                    'resolution': alert.resolution,
                    'html_url': alert.html_url
                })
        except Exception as e:
            print(f"Could not fetch secret alerts for {repo.name}: {e}")
    
    return alerts

def generate_summary_report(code_alerts, secret_alerts):
    """Generate summary statistics"""
    
    # Code scanning summary
    code_by_severity = {}
    code_by_state = {}
    for alert in code_alerts:
        severity = alert['severity']
        state = alert['state']
        code_by_severity[severity] = code_by_severity.get(severity, 0) + 1
        code_by_state[state] = code_by_state.get(state, 0) + 1
    
    # Secret scanning summary
    secret_by_type = {}
    secret_by_state = {}
    for alert in secret_alerts:
        stype = alert['secret_type']
        state = alert['state']
        secret_by_type[stype] = secret_by_type.get(stype, 0) + 1
        secret_by_state[state] = secret_by_state.get(state, 0) + 1
    
    return {
        'generated_at': datetime.now().isoformat(),
        'code_scanning': {
            'total': len(code_alerts),
            'by_severity': code_by_severity,
            'by_state': code_by_state
        },
        'secret_scanning': {
            'total': len(secret_alerts),
            'by_type': secret_by_type,
            'by_state': secret_by_state
        }
    }

def export_to_csv(alerts, filename):
    """Export alerts to CSV"""
    if not alerts:
        return
    
    with open(filename, 'w', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=alerts[0].keys())
        writer.writeheader()
        writer.writerows(alerts)

def main():
    g = Github(GITHUB_TOKEN)
    
    print(f"Generating security report for {ORG_NAME}...")
    
    # Fetch alerts
    code_alerts = get_code_scanning_alerts(g, ORG_NAME)
    secret_alerts = get_secret_scanning_alerts(g, ORG_NAME)
    
    # Generate summary
    summary = generate_summary_report(code_alerts, secret_alerts)
    
    # Export data
    export_to_csv(code_alerts, f'code_scanning_alerts_{datetime.now():%Y%m%d}.csv')
    export_to_csv(secret_alerts, f'secret_scanning_alerts_{datetime.now():%Y%m%d}.csv')
    
    with open(f'security_summary_{datetime.now():%Y%m%d}.json', 'w') as f:
        json.dump(summary, f, indent=2)
    
    # Print summary
    print("\n" + "="*60)
    print("SECURITY REPORT SUMMARY")
    print("="*60)
    print(f"Generated: {summary['generated_at']}")
    print(f"\nCode Scanning Alerts: {summary['code_scanning']['total']}")
    for severity, count in summary['code_scanning']['by_severity'].items():
        print(f"  - {severity}: {count}")
    print(f"\nSecret Scanning Alerts: {summary['secret_scanning']['total']}")
    for state, count in summary['secret_scanning']['by_state'].items():
        print(f"  - {state}: {count}")

if __name__ == "__main__":
    main()

Bash Script for Quick Reports

#!/bin/bash
# quick-security-report.sh - Generate security overview using GitHub CLI

ORG="your-organization"
OUTPUT_DIR="./security-reports"
mkdir -p "$OUTPUT_DIR"

echo "GitHub Advanced Security Report"
echo "Organization: $ORG"
echo "Generated: $(date)"
echo "================================"

# Code scanning summary
echo ""
echo "=== Code Scanning Alerts ==="
gh api "orgs/$ORG/code-scanning/alerts?state=open&per_page=100" \
  --jq 'group_by(.rule.severity) | 
        map({severity: .[0].rule.severity, count: length}) | 
        .[] | "\(.severity): \(.count)"'

# Secret scanning summary
echo ""
echo "=== Secret Scanning Alerts ==="
gh api "orgs/$ORG/secret-scanning/alerts?state=open&per_page=100" \
  --jq 'group_by(.secret_type) | 
        map({type: .[0].secret_type, count: length}) | 
        .[] | "\(.type): \(.count)"'

# Repository coverage
echo ""
echo "=== Security Feature Coverage ==="
gh api "orgs/$ORG/repos?per_page=100" \
  --jq '.[] | select(.archived == false) | 
        "\(.name): Code Scanning=\(.security_and_analysis.code_scanning.status // "disabled"), 
        Secret Scanning=\(.security_and_analysis.secret_scanning.status // "disabled")"'

echo ""
echo "Report complete. Detailed data exported to $OUTPUT_DIR"

Automated Reporting with GitHub Actions

# .github/workflows/security-report.yml
name: Weekly Security Report

on:
  schedule:
    # Run every Monday at 9 AM UTC
    - cron: '0 9 * * 1'
  workflow_dispatch:

jobs:
  generate-report:
    runs-on: ubuntu-latest
    permissions:
      security-events: read
      contents: write
      
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        
      - name: Generate Security Report
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Create report directory
          mkdir -p reports
          
          # Get code scanning alerts
          gh api "repos/${{ github.repository }}/code-scanning/alerts" \
            --paginate > reports/code-scanning.json
          
          # Get secret scanning alerts  
          gh api "repos/${{ github.repository }}/secret-scanning/alerts" \
            --paginate > reports/secret-scanning.json
          
          # Generate summary
          echo "# Security Report - $(date +%Y-%m-%d)" > reports/summary.md
          echo "" >> reports/summary.md
          echo "## Code Scanning" >> reports/summary.md
          echo "Total alerts: $(jq length reports/code-scanning.json)" >> reports/summary.md
          echo "" >> reports/summary.md
          echo "## Secret Scanning" >> reports/summary.md
          echo "Total alerts: $(jq length reports/secret-scanning.json)" >> reports/summary.md
                    
      - name: Upload Report Artifact
        uses: actions/upload-artifact@v4
        with:
          name: security-report-${{ github.run_number }}
          path: reports/
          
      - name: Send Report to Slack
        if: always()
        uses: slackapi/slack-github-action@v1.24.0
        with:
          payload: |
            {
              "text": "Weekly Security Report Generated",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "*Weekly Security Report*\nRepository: ${{ github.repository }}\nGenerated: $(date)"
                  }
                }
              ]
            }            
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Remediation Workflows

GitHub provides several features to help remediate security findings efficiently.

Automated Security Updates with Dependabot

Configure Dependabot to automatically create PRs for security updates:

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "daily"
    open-pull-requests-limit: 10
    
    # Group security updates together
    groups:
      security-updates:
        applies-to: security-updates
        patterns:
          - "*"
    
    # Auto-merge minor and patch security updates
    allow:
      - dependency-type: "direct"
    
    commit-message:
      prefix: "chore(deps):"
      include: "scope"
      
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "weekly"

Auto-merge Security Updates

# .github/workflows/auto-merge-dependabot.yml
name: Auto-merge Dependabot PRs

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: write
  pull-requests: write

jobs:
  auto-merge:
    runs-on: ubuntu-latest
    if: github.actor == 'dependabot[bot]'
    
    steps:
      - name: Dependabot metadata
        id: metadata
        uses: dependabot/fetch-metadata@v1
        with:
          github-token: "${{ secrets.GITHUB_TOKEN }}"
          
      - name: Auto-merge patch and minor updates
        if: |
          steps.metadata.outputs.update-type == 'version-update:semver-patch' ||
          steps.metadata.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 }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Code Scanning Autofix

GitHub’s code scanning can suggest fixes for certain vulnerabilities:

  1. View the code scanning alert
  2. If available, click Generate fix
  3. Review the suggested changes
  4. Create a PR directly from the alert

Currently supported for:

  • JavaScript/TypeScript
  • Python
  • Go
  • Ruby (limited)

Remediation PR Template

Create a template for security remediation PRs:

<!-- .github/PULL_REQUEST_TEMPLATE/security_fix.md -->

## Security Fix

### Alert Reference
- Alert URL: 
- Alert Type: [Code Scanning / Secret Scanning / Dependabot]
- Severity: [Critical / High / Medium / Low]

### Changes Made
- [ ] Vulnerability has been fixed
- [ ] No new vulnerabilities introduced
- [ ] Tests pass
- [ ] Documentation updated (if applicable)

### Root Cause
[Describe what caused this vulnerability]

### Fix Description
[Describe how the vulnerability was fixed]

### Testing
- [ ] Existing tests pass
- [ ] New tests added for the fix
- [ ] Manually tested the fix

### Checklist
- [ ] I have read the [security guidelines](link-to-guidelines)
- [ ] This PR follows our security best practices
- [ ] The fix has been reviewed by a security team member

Bulk Remediation Scripts

#!/bin/bash
# bulk-dismiss-alerts.sh - Dismiss multiple code scanning alerts

REPO="owner/repo"
REASON="used in tests"
COMMENT="These alerts are in test code and don't affect production"

# Get all open alerts in test directories
ALERTS=$(gh api "repos/$REPO/code-scanning/alerts?state=open&per_page=100" \
  --jq '.[] | select(.most_recent_instance.location.path | test("test|spec|__tests__")) | .number')

for alert_number in $ALERTS; do
  echo "Dismissing alert #$alert_number..."
  gh api "repos/$REPO/code-scanning/alerts/$alert_number" \
    -X PATCH \
    -f state=dismissed \
    -f dismissed_reason="$REASON" \
    -f dismissed_comment="$COMMENT"
done

echo "Done! Dismissed $(echo "$ALERTS" | wc -l) alerts."

Organization-Wide Security Policies

Security Policy File

Create a security policy at the organization level:

<!-- .github/SECURITY.md in your .github repository -->

# Security Policy

## Supported Versions

| Version | Supported          |
| ------- | ------------------ |
| 2.x.x   | :white_check_mark: |
| 1.x.x   | :x:                |

## Reporting a Vulnerability

We take security vulnerabilities seriously. If you discover a security issue, please report it responsibly.

### How to Report

1. **Do not** create a public GitHub issue
2. Email security@yourcompany.com with:
   - Description of the vulnerability
   - Steps to reproduce
   - Potential impact
   - Suggested fix (if any)

### Response Timeline

- **Initial response**: Within 24 hours
- **Status update**: Within 72 hours
- **Resolution target**: 30 days for critical, 90 days for others

### Disclosure Policy

- We will acknowledge receipt within 24 hours
- We will provide regular updates on progress
- We will credit reporters (unless anonymity requested)
- We coordinate disclosure timing with reporters

## Security Features

This organization uses GitHub Advanced Security:

- ✅ Code scanning enabled on all repositories
- ✅ Secret scanning with push protection
- ✅ Dependency review on all pull requests
- ✅ Dependabot security updates enabled

Branch Protection Rules

Configure branch protection to enforce security checks:

# Using GitHub CLI to configure branch protection
gh api "repos/{owner}/{repo}/branches/main/protection" \
  -X PUT \
  -H "Accept: application/vnd.github+json" \
  -f "required_status_checks[strict]=true" \
  -f "required_status_checks[contexts][]=CodeQL" \
  -f "required_status_checks[contexts][]=dependency-review" \
  -f "required_pull_request_reviews[required_approving_review_count]=1" \
  -f "required_pull_request_reviews[dismiss_stale_reviews]=true" \
  -f "enforce_admins=true" \
  -f "restrictions=null"

Repository Rulesets

GitHub rulesets provide more granular control:

# Example ruleset configuration (via UI or API)
name: Security Enforcement
target: branch
enforcement: active
conditions:
  ref_name:
    include:
      - refs/heads/main
      - refs/heads/release/*
rules:
  - type: required_status_checks
    parameters:
      required_status_checks:
        - context: "CodeQL"
          integration_id: 0
        - context: "Dependency Review"
          integration_id: 0
      strict_required_status_checks_policy: true
  - type: pull_request
    parameters:
      required_approving_review_count: 1
      dismiss_stale_reviews_on_push: true
      require_code_owner_review: true

Best Practices for GHAS Management

Initial Rollout Strategy

  1. Start with Pilot Repositories

    • Enable on 3-5 representative repositories
    • Learn alert patterns and false positive rates
    • Document triage procedures
  2. Triage Existing Alerts

    • Prioritize critical and high severity
    • Dismiss false positives with clear documentation
    • Create remediation plan for legitimate issues
  3. Gradual Expansion

    • Roll out to additional repositories in phases
    • Use security overview to track progress
    • Adjust configurations based on learnings
  4. Full Coverage

    • Enable on all repositories
    • Enforce through organization policies
    • Monitor and maintain continuously

Alert Triage Process

## Alert Triage Workflow

1. **Initial Review** (< 1 hour)
   - Verify alert is legitimate (not false positive)
   - Assess severity and potential impact
   - Assign to appropriate team member

2. **Analysis** (< 1 day)
   - Understand the vulnerability context
   - Determine exploitability
   - Identify affected code paths

3. **Prioritization**
   - Critical: Fix within 24 hours
   - High: Fix within 1 week
   - Medium: Fix within 1 sprint
   - Low: Fix as time permits

4. **Remediation**
   - Create issue/ticket for tracking
   - Develop and test fix
   - Submit PR with security fix template
   - Request security review

5. **Verification**
   - Confirm alert is closed
   - Run regression tests
   - Update documentation if needed

Maintenance Schedule

# Recommended maintenance cadence

Weekly:
  - Review new alerts from security overview
  - Triage and assign critical/high severity alerts
  - Check Dependabot PR queue

Monthly:
  - Review security feature coverage
  - Update custom query packs if needed
  - Review dismissed alerts for patterns

Quarterly:
  - Full security posture review
  - Update security policies
  - Review and rotate service account tokens
  - Training refresher for team

Annually:
  - Comprehensive security audit
  - GHAS configuration review
  - Update incident response procedures

Integration with Development Workflow

# Example PR workflow with security gates
# .github/workflows/pr-security-checks.yml

name: PR Security Checks

on:
  pull_request:
    branches: [main, develop]

jobs:
  security-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run CodeQL Analysis
        uses: github/codeql-action/analyze@v3
        
      - name: Dependency Review
        uses: actions/dependency-review-action@v4
        with:
          fail-on-severity: high
          
      - name: Check for Secrets
        uses: trufflesecurity/trufflehog@main
        with:
          path: ./
          
      - name: Security Summary
        if: always()
        run: |
          echo "## Security Check Summary" >> $GITHUB_STEP_SUMMARY
          echo "- CodeQL: Complete" >> $GITHUB_STEP_SUMMARY
          echo "- Dependency Review: Complete" >> $GITHUB_STEP_SUMMARY
          echo "- Secret Scanning: Complete" >> $GITHUB_STEP_SUMMARY          

Troubleshooting Common Issues

Code Scanning Not Running

Problem: CodeQL workflow not triggering or failing

Solutions:

  1. Check workflow syntax
  2. Verify language detection
  3. Check for build failures
  4. Review action logs for specific errors
# Debug CodeQL analysis
- name: Initialize CodeQL
  uses: github/codeql-action/init@v3
  with:
    languages: javascript
    debug: true

High False Positive Rate

Problem: Too many alerts that aren’t real vulnerabilities

Solutions:

  1. Review and adjust query suites
  2. Add path exclusions for test code
  3. Use inline suppressions where appropriate
  4. Report false positives to improve queries
# Exclude test directories
config-file: |
  paths-ignore:
    - '**/test/**'
    - '**/tests/**'
    - '**/__tests__/**'
    - '**/*.test.*'
    - '**/*.spec.*'  

Secret Scanning Missing Secrets

Problem: Known secrets not being detected

Solutions:

  1. Verify secret format matches known patterns
  2. Create custom patterns for internal secrets
  3. Check if secret is in excluded paths
  4. Report to GitHub partner program

Dependency Review Blocking PRs

Problem: PRs blocked by vulnerable dependencies

Solutions:

  1. Update the vulnerable dependency
  2. If update not available, assess risk and allow temporarily
  3. Use allow-ghsas to bypass specific advisories
  4. Create security exception process

Conclusion

GitHub Advanced Security provides a comprehensive suite of tools for securing your codebase. By properly configuring code scanning, secret scanning, and dependency review, you can identify and remediate vulnerabilities before they reach production.

Key takeaways:

  1. Enable Progressively: Start with pilot repositories, then expand
  2. Automate Where Possible: Use Dependabot, auto-merge, and scheduled workflows
  3. Integrate into Workflow: Make security checks part of the PR process
  4. Monitor Continuously: Use security overview for ongoing visibility
  5. Document Everything: Clear policies and procedures improve response times
  6. Train Your Team: Ensure everyone understands how to use and respond to GHAS

The investment in setting up and maintaining GitHub Advanced Security pays dividends through:

  • Reduced vulnerability exposure
  • Faster security remediation
  • Better compliance posture
  • Improved developer security awareness

Start your GitHub Advanced Security journey today by enabling features on a pilot repository and building from there.

Resources