how-to

How to Set Up Semgrep GitHub Action for Code Scanning

Set up the Semgrep GitHub Action for automated code scanning. Covers workflow YAML, rulesets, PR comments, SARIF upload, custom rules, and caching.

Published:

Why run Semgrep as a GitHub Action

Semgrep is a fast, open-source static analysis engine that scans code for security vulnerabilities, bugs, and enforced coding patterns. Running it as a GitHub Action means every pull request and push to your main branch is automatically checked against thousands of rules before code reaches production. There is no manual step, no context switching to a separate tool, and no waiting minutes for results. The median Semgrep CI scan finishes in about 10 seconds.

The Semgrep GitHub Action fits into two workflows. The first is standalone mode, where you specify rulesets directly in your YAML file and Semgrep runs without any external service. The second is cloud-connected mode, where you link your GitHub repository to Semgrep Cloud (free for up to 10 contributors) and get PR comments, a findings dashboard, AI-powered triage, and policy management from a web interface. Both approaches use the same underlying scan engine.

This guide covers every aspect of the semgrep github actions workflow - from the basic YAML file to SARIF upload for GitHub Security, custom rules in CI, caching for faster builds, monorepo support, and troubleshooting common failures. By the end, you will have a production-ready semgrep code scanning github configuration that catches real vulnerabilities without slowing down your team.

Semgrep code review tool homepage screenshot
Semgrep homepage

Prerequisites

Before setting up the Semgrep GitHub Action, confirm you have the following:

  • A GitHub repository where you have admin or write access to create workflow files
  • Familiarity with GitHub Actions basics (workflow YAML syntax, secrets, status checks)
  • Optionally, a Semgrep Cloud account at semgrep.dev if you want PR comments and dashboard reporting

If you have not used Semgrep before, the how to setup Semgrep guide covers local CLI installation and your first scan. This guide focuses specifically on the GitHub Actions integration.

Basic Semgrep GitHub Action workflow

The simplest way to add Semgrep to your repository is a standalone workflow that runs the scan using registry rulesets.

Create the workflow file

Create .github/workflows/semgrep.yml in your repository:

name: Semgrep

on:
  pull_request: {}
  push:
    branches:
      - main

jobs:
  semgrep:
    name: Semgrep Scan
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Run Semgrep
        run: semgrep scan --config p/default --error

This workflow triggers on every pull request and every push to the main branch. The --config p/default flag loads the curated default ruleset, which contains high-confidence security and correctness rules with low false positive rates. The --error flag causes Semgrep to return a non-zero exit code when findings are detected, which marks the GitHub Actions check as failed.

The container: image: semgrep/semgrep directive runs the job inside the official Semgrep Docker image, ensuring a consistent environment with the latest version of the engine pre-installed. This avoids any Python dependency management in your workflow.

Trigger configuration options

You can customize when the workflow runs:

on:
  pull_request:
    branches:
      - main
      - develop
  push:
    branches:
      - main
  schedule:
    - cron: "0 0 * * 1"  # Weekly scan every Monday at midnight

The schedule trigger is useful for running full-repository scans on a recurring basis. This catches issues in code that was merged before Semgrep was enabled or when new rules are added to the registry that detect patterns already present in your codebase.

Connecting to Semgrep Cloud for PR comments

The standalone workflow catches findings but only surfaces them as a pass/fail status check. To get inline PR comments that show developers exactly what the issue is and how to fix it, connect your workflow to Semgrep Cloud.

Step 1 - Create a Semgrep Cloud account

Sign up at semgrep.dev using your GitHub account. Create an organization that corresponds to your GitHub organization. Navigate to Settings and generate an API token. This token authenticates your CI scans and enables PR comments, finding management, and the web dashboard.

Step 2 - Install the Semgrep GitHub App

In Semgrep Cloud, go to Settings, then Source Code Managers, and click “Add GitHub.” Authorize the Semgrep GitHub App and select which repositories or organizations to grant access to. The GitHub App is what enables Semgrep to post inline comments on pull requests - the CI workflow detects findings, uploads them to Semgrep Cloud, and the GitHub App delivers the comments.

Step 3 - Add the token to GitHub secrets

In your GitHub repository, go to Settings, then Secrets and variables, then Actions. Click “New repository secret,” name it SEMGREP_APP_TOKEN, and paste the token you generated in Semgrep Cloud. This secret is referenced in your workflow file.

Step 4 - Update the workflow to use semgrep ci

Replace your standalone workflow with the cloud-connected version:

name: Semgrep

on:
  pull_request: {}
  push:
    branches:
      - main

jobs:
  semgrep:
    name: Semgrep Scan
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Run Semgrep
        run: semgrep ci
        env:
          SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}

The semgrep ci command differs from semgrep scan in several important ways. It performs diff-aware scanning on pull requests, meaning it only analyzes files that changed in the PR rather than the entire repository. It pulls rule configuration from your Semgrep Cloud policy instead of requiring --config flags. It uploads results to the cloud dashboard. And it triggers PR comments through the GitHub App for any new findings.

How PR comments look

When Semgrep detects an issue in changed code, the GitHub App posts an inline comment on the exact line of the pull request. The comment includes the rule ID, severity level, a plain-language explanation of the vulnerability, and often a suggested fix. Developers can respond by fixing the code, marking the finding as a false positive in Semgrep Cloud, or adding a # nosemgrep: rule-id inline suppression with justification.

Rule modes in Semgrep Cloud control comment behavior. Rules set to Block mode produce comments that also fail the status check and prevent merging. Rules set to Comment mode produce comments but allow the PR to merge. Rules set to Monitor mode track findings in the dashboard without posting any comment on the PR.

Ruleset selection for your workflow

Choosing the right rulesets determines what your semgrep ci cd github workflow catches and how much noise it generates. Here is a breakdown of the most useful options.

Core rulesets

p/default is the recommended starting point. It contains approximately 600 high-confidence rules curated by the Semgrep team covering security vulnerabilities, correctness bugs, and best practices across all supported languages. False positive rates are low, and every rule has been validated against real-world codebases.

p/security-audit is a broader set with moderate-confidence rules. It catches more potential issues but requires more triage bandwidth. Enable this after your team is comfortable with the baseline from p/default.

p/owasp-top-ten maps rules to OWASP Top 10 categories - injection, broken authentication, sensitive data exposure, and others. This set is valuable for compliance-driven teams that need to demonstrate OWASP coverage.

Language-specific rulesets

Add targeted rulesets for your stack:

- name: Run Semgrep
  run: >
    semgrep scan
    --config p/default
    --config p/python
    --config p/javascript
    --config p/golang
    --error

Each language set includes rules for framework-specific patterns. The p/python set covers Django and Flask security. The p/javascript set covers Express, React, and Node.js patterns. The p/golang set covers common Go error handling and concurrency pitfalls.

Infrastructure rulesets

For repositories that include infrastructure-as-code files, add the relevant sets:

- name: Run Semgrep
  run: >
    semgrep scan
    --config p/default
    --config p/terraform
    --config p/dockerfile
    --config p/kubernetes
    --error

These catch misconfigurations like running containers as root, exposing unnecessary ports, missing encryption settings on cloud resources, and overly permissive IAM policies.

For a detailed comparison of Semgrep’s rule-based approach with CodeQL’s semantic analysis, see our Semgrep vs CodeQL comparison.

Uploading SARIF to GitHub Security tab

GitHub’s Security tab provides a centralized view of code scanning alerts. Uploading Semgrep results in SARIF format integrates findings alongside CodeQL and other scanning tools in a single dashboard.

SARIF upload workflow

name: Semgrep

on:
  pull_request: {}
  push:
    branches:
      - main

jobs:
  semgrep:
    name: Semgrep Scan
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    permissions:
      contents: read
      security-events: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Run Semgrep
        run: semgrep scan --config p/default --sarif --output semgrep.sarif

      - name: Upload SARIF to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: semgrep.sarif
        if: always()

The permissions: security-events: write line grants the workflow the ability to upload SARIF data to the GitHub Security tab. The if: always() on the upload step ensures results are uploaded even when Semgrep exits with a non-zero code due to findings. Without this, the upload step would be skipped on scan failure.

Combining SARIF upload with Semgrep Cloud

You can use both semgrep sarif github upload and Semgrep Cloud PR comments in the same workflow:

jobs:
  semgrep:
    name: Semgrep Scan
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    permissions:
      contents: read
      security-events: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Run Semgrep CI
        run: semgrep ci --sarif --output semgrep.sarif
        env:
          SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}

      - name: Upload SARIF to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: semgrep.sarif
        if: always()

This gives you the best of both worlds - inline PR comments from the Semgrep GitHub App and centralized alert management in the GitHub Security tab.

Viewing SARIF results

After the first successful upload, navigate to your repository’s Security tab, then Code scanning. You will see Semgrep findings listed alongside any CodeQL alerts. Each alert shows the rule ID, severity, file location, and a description. You can dismiss alerts, create issues from them, or filter by tool, severity, and branch.

Running custom rules in GitHub Actions

Custom rules let you enforce patterns specific to your codebase - deprecated API usage, internal security standards, required error handling patterns, and more. Running them in CI ensures every PR is checked against your team’s conventions. For an in-depth guide on writing rules, see Semgrep custom rules.

Store rules in your repository

Create a .semgrep/ directory at the root of your repository and add your custom rule YAML files:

.semgrep/
  security/
    no-hardcoded-secrets.yaml
    sql-injection.yaml
  correctness/
    required-error-handling.yaml
  style/
    no-deprecated-apis.yaml

Reference custom rules in the workflow

- name: Run Semgrep
  run: >
    semgrep scan
    --config p/default
    --config .semgrep/
    --error

Semgrep recursively loads all YAML files from the .semgrep/ directory and runs them alongside the registry ruleset. Custom rules and registry rules execute in a single pass, so there is no performance penalty for adding your own checks.

Example custom rule for CI

Here is a rule that detects direct database calls outside the data access layer - a pattern enforcement that is only meaningful in the context of your project architecture:

rules:
  - id: no-direct-db-calls-in-handlers
    patterns:
      - pattern: db.query(...)
      - pattern-not-inside: |
          func $FUNC(...) {
            ...
          }
    paths:
      include:
        - "handlers/"
        - "api/"
      exclude:
        - "dal/"
        - "repository/"
    message: >
      Direct database calls detected in handler layer.
      Use the data access layer (dal/) for all database
      operations to maintain separation of concerns.
    severity: WARNING
    languages:
      - go

Sharing rules across repositories

If you maintain custom rules in a separate private repository, check it out in a prior step:

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

  - name: Checkout shared rules
    uses: actions/checkout@v4
    with:
      repository: your-org/semgrep-rules
      path: shared-rules
      token: ${{ secrets.RULES_REPO_TOKEN }}

  - name: Run Semgrep
    run: >
      semgrep scan
      --config p/default
      --config shared-rules/
      --error

This pattern keeps your security rules centralized while applying them consistently across all repositories in your organization.

Caching Semgrep rules for faster scans

Every time Semgrep runs with a registry ruleset like p/default, it downloads the rules from the Semgrep Registry. Caching these downloaded rules saves network time and reduces scan startup latency.

Add caching to your workflow

jobs:
  semgrep:
    name: Semgrep Scan
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Cache Semgrep rules
        uses: actions/cache@v4
        with:
          path: ~/.semgrep
          key: semgrep-rules-${{ hashFiles('.github/workflows/semgrep.yml') }}
          restore-keys: |
            semgrep-rules-

      - name: Run Semgrep
        run: semgrep scan --config p/default --error

The cache key is based on a hash of your workflow file. When you change the rulesets in your workflow, the cache key changes and Semgrep downloads fresh rules. The restore-keys fallback ensures a partial cache hit still saves time even when the exact key does not match.

Weekly cache invalidation

If you want rules to refresh weekly to pick up new additions from the Semgrep Registry, use a date-based cache key:

- name: Cache Semgrep rules
  uses: actions/cache@v4
  with:
    path: ~/.semgrep
    key: semgrep-rules-${{ steps.date.outputs.week }}
    restore-keys: |
      semgrep-rules-

- name: Get week number
  id: date
  run: echo "week=$(date +%Y-%W)" >> $GITHUB_OUTPUT

This invalidates the cache every Monday, ensuring your scans use rules that are no more than a week old while still saving download time on every other run during the week.

Monorepo support

Monorepos require targeted scanning to avoid running every ruleset against every directory and to keep scan times fast. The Semgrep GitHub Action supports monorepos through path filters, targeted config, and multiple workflow files.

Path-filtered triggers

Only run Semgrep when files in relevant directories change:

on:
  pull_request:
    paths:
      - "services/api/**"
      - "services/auth/**"
      - "libs/shared/**"

This prevents the workflow from running when only documentation, CI configuration, or unrelated services change.

Per-service ruleset configuration

Different services in a monorepo may use different languages and frameworks. Configure rulesets accordingly:

jobs:
  scan-api:
    name: Scan API Service
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - uses: actions/checkout@v4
      - run: semgrep scan --config p/default --config p/python services/api/

  scan-frontend:
    name: Scan Frontend
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - uses: actions/checkout@v4
      - run: semgrep scan --config p/default --config p/javascript services/frontend/

  scan-infra:
    name: Scan Infrastructure
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - uses: actions/checkout@v4
      - run: semgrep scan --config p/terraform --config p/dockerfile infra/

Running these as separate jobs enables parallel execution. Each service is scanned with only the relevant rulesets, reducing both scan time and false positives from language-irrelevant rules.

Multiple workflow files

For large monorepos, consider creating separate workflow files for each service. This gives each team ownership over their scanning configuration:

.github/workflows/
  semgrep-api.yml
  semgrep-frontend.yml
  semgrep-infra.yml
  semgrep-mobile.yml

Each workflow has its own path filters, rulesets, and branch protection configuration. Teams can modify their scanning rules without affecting other services.

Advanced workflow configuration

Severity-based blocking

Block PRs only for critical findings while allowing lower-severity issues to pass:

- name: Run Semgrep (blocking)
  run: semgrep scan --config p/default --severity ERROR --error

- name: Run Semgrep (advisory)
  run: semgrep scan --config p/security-audit --severity WARNING --json > advisory-findings.json
  continue-on-error: true

The first step fails the workflow for ERROR-level findings. The second step runs a broader ruleset but uses continue-on-error: true so that WARNING-level findings are visible in the logs without blocking the PR.

Matrix strategy for multiple rulesets

Use a matrix to run different rulesets in parallel:

jobs:
  semgrep:
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    strategy:
      matrix:
        config:
          - p/default
          - p/security-audit
          - .semgrep/
    steps:
      - uses: actions/checkout@v4
      - run: semgrep scan --config ${{ matrix.config }} --error

Timeout and resource limits

Prevent scans from hanging on very large files or complex patterns:

- name: Run Semgrep
  run: >
    semgrep scan
    --config p/default
    --timeout 30
    --max-memory 4000
    --max-target-bytes 1000000
    --error
  timeout-minutes: 10

The --timeout 30 sets a 30-second per-rule timeout. The --max-memory 4000 caps memory usage at 4 GB. The --max-target-bytes 1000000 skips files larger than 1 MB. The timeout-minutes: 10 on the step level is a GitHub Actions safeguard that kills the entire step if it exceeds 10 minutes.

Configuring branch protection

After the Semgrep workflow is running, configure GitHub branch protection to require it to pass before merging:

  1. Go to your repository Settings, then Branches (or Rulesets for newer repository configurations)
  2. Edit or create a branch protection rule for your main branch
  3. Enable “Require status checks to pass before merging”
  4. Search for and add the “Semgrep Scan” check
  5. Save your changes

With this in place, any pull request that triggers blocking Semgrep findings cannot be merged until the findings are resolved - either by fixing the code, suppressing the finding with justification, or triaging it as a false positive in Semgrep Cloud.

CodeAnt AI as an alternative

If you are looking for a broader automated code review solution that goes beyond static analysis, CodeAnt AI is worth evaluating. Priced at $24-40 per user per month, CodeAnt AI combines SAST, anti-pattern detection, code quality scoring, and AI-driven review suggestions into a single GitHub integration. It installs as a GitHub App and provides PR comments without requiring workflow YAML configuration.

CodeAnt AI is particularly relevant for teams that want a unified tool covering both security scanning and code quality review rather than assembling separate tools for each concern. For a broader look at SAST options, see our best SAST tools roundup, and for other Semgrep alternatives, check the Semgrep alternatives comparison.

Troubleshooting common issues

Workflow does not trigger on pull requests

If the Semgrep workflow is not running when you open a pull request, check the following:

  • Verify the workflow file exists at .github/workflows/semgrep.yml and is present on the default branch (usually main). GitHub requires the workflow file to be merged to the default branch before it triggers on PRs.
  • Confirm the on: section includes pull_request: {}. A missing pull_request trigger means the workflow only runs on push events.
  • Check for YAML syntax errors. GitHub silently ignores malformed workflow files. Validate your YAML with a linter or the GitHub Actions workflow editor.
  • Look at the Actions tab in your repository for any workflow run errors or queued runs.

SEMGREP_APP_TOKEN authentication errors

When semgrep ci fails with “Invalid API token” or “Authentication failed”:

  • Verify the secret is named exactly SEMGREP_APP_TOKEN in your repository Settings under Secrets and variables, then Actions. The name is case-sensitive.
  • Check that the token has not expired in Semgrep Cloud under Settings, then Tokens.
  • Ensure the repository is connected to the correct organization in Semgrep Cloud. If you belong to multiple organizations, the token must match the one that owns the repository connection.
  • Regenerate the token in Semgrep Cloud and update the GitHub secret if the issue persists.

Scan takes too long

If your Semgrep scan exceeds acceptable CI time:

  • Switch from full scans to diff-aware scanning by using semgrep ci instead of semgrep scan. Diff-aware scanning only analyzes changed files on pull requests.
  • Add a .semgrepignore file to exclude test files, vendored code, generated files, and build artifacts. See the how to setup Semgrep guide for a comprehensive .semgrepignore template.
  • Reduce the number of rulesets. Start with p/default alone before adding broader sets like p/security-audit.
  • Set --max-target-bytes 500000 to skip files larger than 500 KB that are unlikely to be hand-written source code.
  • Enable rule caching as described in the caching section above.

Out of memory errors in CI

Semgrep can consume significant memory on very large files or when running many rules:

- name: Run Semgrep
  run: >
    semgrep scan
    --config p/default
    --max-memory 4000
    --jobs 2
    --error

The --max-memory 4000 flag caps Semgrep at 4 GB of RAM. The --jobs 2 flag reduces parallelism, trading scan speed for lower memory usage. Add large non-source files like package-lock.json, minified bundles, and compiled assets to your .semgrepignore file.

Findings in code you cannot change

When Semgrep flags vendored dependencies, generated code, or migration files:

  • Add the directories to .semgrepignore (for example, vendor/, generated/, migrations/)
  • Use inline # nosemgrep: rule-id comments for individual suppressions in files you own but where the pattern is intentional
  • In Semgrep Cloud, triage findings as “Ignored” with a reason so they do not reappear on future scans

SARIF upload fails with permission errors

If the upload-sarif step fails with a 403 or permission denied error:

  • Ensure your job includes permissions: security-events: write in the workflow YAML
  • Check that GitHub Advanced Security is enabled for the repository (required for private repositories to use code scanning)
  • For organization repositories, verify that the organization allows code scanning uploads from Actions

Custom rules not being picked up

If your custom rules in .semgrep/ are not running:

  • Verify the rule files have a .yaml or .yml extension
  • Run semgrep --validate --config .semgrep/ locally to check for syntax errors
  • Ensure the --config .semgrep/ path is correct relative to the repository root
  • Check that the languages field in each rule matches the file types present in your codebase

Semgrep pricing for GitHub Actions usage

The Semgrep open-source engine is free and always will be. Running semgrep scan with registry rulesets in GitHub Actions costs nothing beyond your GitHub Actions minutes.

Semgrep Cloud - which adds PR comments, the findings dashboard, AI-powered triage with Semgrep Assistant, and cross-file analysis with Pro rules - is free for up to 10 contributors. Beyond that, the Team plan costs $35 per contributor per month. For a detailed breakdown, see our Semgrep pricing guide.

GitHub Actions minutes are free for public repositories. For private repositories, the GitHub Free plan includes 2,000 minutes per month. Since Semgrep scans typically complete in under 60 seconds, even the free tier provides enough minutes for hundreds of scans per month.

Summary

Setting up the Semgrep GitHub Action gives your team automated security scanning on every pull request with minimal configuration. The basic standalone workflow takes five minutes to create. Adding Semgrep Cloud for PR comments and dashboard reporting takes another five minutes. From there, you can incrementally add SARIF upload for the GitHub Security tab, custom rules for project-specific patterns, caching for faster scans, and per-service configurations for monorepos.

Start with the p/default ruleset and the simplest workflow that meets your needs. Expand coverage and strictness over your first few weeks as your team builds familiarity with the findings. The goal is a scanning configuration that developers trust and act on - not one that generates so many alerts that everyone learns to ignore it.

For teams evaluating their SAST tool options more broadly, our Semgrep alternatives comparison covers how Semgrep stacks up against CodeQL, SonarQube, Checkmarx, and other scanners across speed, accuracy, language support, and pricing.

Frequently Asked Questions

How do I set up the Semgrep GitHub Action?

Create a workflow file at .github/workflows/semgrep.yml that triggers on pull_request and push events. Use the official semgrep/semgrep Docker container image and run 'semgrep ci' as the scan command. Add your SEMGREP_APP_TOKEN as a GitHub Actions secret to connect with Semgrep Cloud for PR comments and dashboard reporting. The entire setup takes under 10 minutes.

What is the difference between semgrep ci and semgrep scan in GitHub Actions?

The 'semgrep ci' command is purpose-built for CI/CD environments. It performs diff-aware scanning on pull requests (only checking changed files), uploads results to Semgrep Cloud, posts PR comments, and pulls rule configuration from your cloud policy. The 'semgrep scan' command runs a full scan with locally specified rulesets and outputs results to stdout or a file. Use 'semgrep ci' when connected to Semgrep Cloud and 'semgrep scan' for standalone workflows.

How do I upload Semgrep results to GitHub Security tab?

Add a SARIF output step to your workflow by running 'semgrep scan --config auto --sarif --output semgrep.sarif', then use the github/codeql-action/upload-sarif@v3 action to upload the file. Your workflow job needs the 'security-events: write' permission. Results appear under the Security tab as Code Scanning alerts alongside CodeQL findings.

How do I get Semgrep PR comments on GitHub pull requests?

Connect your repository to Semgrep Cloud at semgrep.dev, install the Semgrep GitHub App from the Source Code Managers settings page, add your SEMGREP_APP_TOKEN to GitHub Actions secrets, and use 'semgrep ci' in your workflow. Semgrep automatically posts inline comments on PR lines where new findings are detected, including the rule ID, severity, explanation, and remediation guidance.

How do I cache Semgrep rules in GitHub Actions to speed up scans?

Use the actions/cache action to cache the ~/.semgrep directory where Semgrep stores downloaded rules. Set the cache key to a hash of your Semgrep configuration file or use a weekly rolling key. This avoids downloading the full rule registry on every workflow run and typically saves 10-30 seconds per scan.

Does the Semgrep GitHub Action work with monorepos?

Yes. Use path filters in your workflow's on.pull_request.paths configuration to trigger scans only when relevant directories change. For targeted scanning, pass specific paths to the semgrep scan command. You can also create multiple workflow files - one per service or package - each with its own ruleset configuration and path filters.

How do I run custom Semgrep rules in GitHub Actions?

Store your custom rule YAML files in a directory like .semgrep/ in your repository. Reference them in your workflow with '--config .semgrep/' alongside registry rulesets like '--config p/default'. The custom rules are automatically picked up from the checked-out repository code. You can also reference rules from a separate private repository by checking it out in a prior workflow step.

Why is my Semgrep GitHub Action failing with an authentication error?

Authentication errors with 'semgrep ci' typically mean the SEMGREP_APP_TOKEN secret is missing, expired, or incorrectly named. Verify the secret exists in your repository Settings under Secrets and variables. Check that the token has not expired in Semgrep Cloud under Settings. Ensure the repository is connected to the correct Semgrep Cloud organization. If the issue persists, regenerate the token and update the GitHub secret.

How do I make the Semgrep GitHub Action block PR merges?

Configure the Semgrep workflow to exit with a non-zero code when findings are detected by using the '--error' flag with 'semgrep scan' or by setting rules to Block mode in Semgrep Cloud. Then enable branch protection in your GitHub repository settings by requiring the Semgrep status check to pass before merging. Any PR with blocking findings will be prevented from merging.

How long does the Semgrep GitHub Action take to run?

Semgrep is one of the fastest SAST tools available. Diff-aware scans on pull requests typically complete in 10-30 seconds because only changed files are analyzed. Full repository scans on push to main usually finish in under 60 seconds for most codebases. Adding SARIF upload or multiple rulesets may add a few seconds. Rule caching can further reduce startup time.

Can I run Semgrep alongside CodeQL in GitHub Actions?

Yes, and many teams do exactly this. Semgrep and CodeQL complement each other well - Semgrep provides fast pattern-based scanning with 10-second median scan times, while CodeQL performs deeper semantic analysis that takes longer but catches different vulnerability classes. Both tools can upload SARIF results to the GitHub Security tab where findings are deduplicated and displayed together.

What are the best Semgrep rulesets to use in GitHub Actions?

Start with 'p/default' which contains high-confidence security and correctness rules with low false positive rates. Add 'p/security-audit' when you want broader security coverage and have bandwidth to triage additional findings. For infrastructure code, add 'p/terraform', 'p/dockerfile', or 'p/kubernetes'. Language-specific sets like 'p/python', 'p/javascript', and 'p/golang' provide targeted checks for those ecosystems.

Explore More

Free Newsletter

Stay ahead with AI dev tools

Weekly insights on AI code review, static analysis, and developer productivity. No spam, unsubscribe anytime.

Join developers getting weekly AI tool insights.

Related Articles