# GitHub Actions for Product Security

> **Intro:** GitHub Actions is not just a CI system. It is also a practical control plane for product security: dependency review, code scanning, secret prevention, provenance, and safer cloud access can all be implemented as policy-bearing workflows.
>
> **What this page includes**
>
> * what GitHub Actions is and why it matters to Product Security
> * where GitHub Actions is strong and where teams misuse it
> * 5 practical workflow examples
> * web UI setup notes and defensive defaults

## What it is

GitHub Actions is GitHub’s workflow automation system. It runs jobs defined in YAML files under `.github/workflows/`.

In a Product Security context, GitHub Actions commonly becomes the place where teams:

* block insecure dependency changes before merge;
* run SAST or code scanning;
* generate SBOMs and provenance;
* authenticate to cloud providers without long-lived secrets;
* standardize security checks across many repositories.

## Why Product Security teams care

GitHub Actions is useful to Product Security because it sits close to:

* pull requests;
* branch protection;
* dependency changes;
* code scanning results;
* source provenance;
* repository and organization policy.
* ownership and disclosure defaults such as `CODEOWNERS`, `SECURITY.md`, and org-level templates.

That means it can enforce security where engineers already work, instead of asking them to leave the repo and use a separate process.

## When GitHub Actions is a strong fit

Use GitHub Actions heavily when you want:

* security checks at pull-request time;
* organization-wide reusable workflows;
* GitHub-native CodeQL and dependency review;
* artifact attestations and provenance;
* OIDC-based deployments to cloud platforms;
* consistent guardrails across many repositories.

## When not to overload GitHub Actions

GitHub Actions is not the right place for every test.

Keep these outside fast PR checks when needed:

* long-running DAST against production;
* full manual penetration testing;
* complex environment-specific fuzzing;
* sensitive signing operations that belong in isolated release infrastructure.

Use **three speeds**:

1. **fast PR checks** — dependency review, linting, lightweight SAST;
2. **merge or main-branch checks** — deeper scans, SBOM generation, attestations;
3. **out-of-band or release-stage checks** — heavyweight or manual validation.

***

## Hardening defaults before you add more workflows

### Repository UI steps

#### Settings → Actions → General

Review:

* who can create and approve workflows;
* whether local actions and reusable workflows are allowed;
* whether unverified marketplace actions are restricted;
* default `GITHUB_TOKEN` permissions.

**Good default:** read-only by default, then grant explicit write permissions per workflow.

#### Settings → Security / Code security and analysis

Depending on plan and features enabled, review:

* dependency graph;
* dependency review;
* code scanning;
* secret scanning;
* push protection.

#### Settings → Branches

Make security workflows count:

* require status checks before merge;
* require pull request reviews;
* protect the default branch;
* block direct pushes for most contributors.

***

For a repository-baseline view that complements workflow hardening, see [Repository Governance — CODEOWNERS, SECURITY.md, and Default Files](/devsecops-cicd-and-supply-chain/index-1/repository-governance-codeowners-security-md-and-default-files.md).

## Security pitfalls teams hit first

| Pitfall                                                          | Why it happens        | Better pattern                                                  |
| ---------------------------------------------------------------- | --------------------- | --------------------------------------------------------------- |
| default broad `GITHUB_TOKEN` permissions                         | convenience           | set minimal permissions per job                                 |
| unpinned third-party actions                                     | fast copy-paste       | pin to a full commit SHA where possible                         |
| long-lived cloud secrets in repo settings                        | easy setup            | OIDC to cloud provider                                          |
| one reusable workflow copied into 50 repos manually              | drift                 | central reusable workflows                                      |
| self-hosted runner used for untrusted PRs and production deploys | poor trust separation | split runners by trust, or use GitHub-hosted for low-trust jobs |
| treating Actions as “just CI”                                    | missed security value | use it as policy and evidence plane                             |

***

## Example 1 - Dependency Review gate for pull requests

**What it does**

Blocks pull requests that introduce vulnerable dependencies.

**File**

`.github/workflows/dependency-review.yml`

See: [`snippets/ci/github-actions/dependency-review.yml`](https://github.com/D3One/Product-Security-Gitbook/blob/main/snippets/ci/github-actions/dependency-review.yml)

```yaml
name: dependency-review

on:
  pull_request:
    branches: [ main ]

permissions:
  contents: read

jobs:
  dependency-review:
    runs-on: ubuntu-latest
    steps:
      - name: Dependency Review
        uses: actions/dependency-review-action@v4
        with:
          fail-on-severity: high
          allow-licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause
```

**Why Product Security likes it**

* fast PR feedback;
* no separate scanner UI needed for basic dependency change review;
* easy to mark as a required status check.

**When to use**

* almost every app repo with lockfiles or package manifests.

***

## Example 2 - CodeQL code scanning workflow

**What it does**

Runs GitHub-native code scanning with CodeQL and publishes alerts in the Security tab.

**File**

`.github/workflows/codeql.yml`

See: [`snippets/ci/github-actions/codeql.yml`](https://github.com/D3One/Product-Security-Gitbook/blob/main/snippets/ci/github-actions/codeql.yml)

```yaml
name: codeql

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: "17 3 * * 1"

permissions:
  contents: read
  security-events: write
  actions: read

jobs:
  analyze:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        language: [ "javascript", "python" ]
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
      - uses: github/codeql-action/autobuild@v3
      - uses: github/codeql-action/analyze@v3
```

**Why Product Security likes it**

* first-class GitHub integration;
* results live where developers already review PRs and alerts;
* useful as a baseline SAST layer.

**Operational note**

Default setup can be good enough for many repos. Advanced setup is better when you need explicit languages, build steps, paths, or schedules.

***

## Example 3 - OIDC to AWS instead of static cloud keys

**What it does**

Lets a workflow obtain short-lived AWS credentials using GitHub’s OIDC integration instead of storing long-lived AWS keys in GitHub secrets.

**File**

`.github/workflows/deploy-oidc-aws.yml`

See: [`snippets/ci/github-actions/aws-oidc-deploy.yml`](https://github.com/D3One/Product-Security-Gitbook/blob/main/snippets/ci/github-actions/aws-oidc-deploy.yml)

```yaml
name: deploy-with-oidc

on:
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials from OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-prod-deploy
          aws-region: eu-central-1

      - name: Verify identity
        run: aws sts get-caller-identity

      - name: Deploy example
        run: |
          aws s3 sync dist/ s3://example-prod-site/
```

**Why this is better**

* no long-lived AWS access key in GitHub;
* access is scoped by repository, branch, environment, and role trust policy;
* easier to rotate because there is no duplicated secret to rotate in GitHub.

**Common pitfall**

People enable OIDC but make the cloud trust conditions too broad. Restrict by repo, branch, environment, or reusable workflow identity.

***

## Example 4 - Build artifact attestation and verification

**What it does**

Creates provenance for a build artifact and later verifies it.

**Files**

* `.github/workflows/attest-build.yml`
* local verification with GitHub CLI

See: [`snippets/ci/github-actions/artifact-attestation.yml`](https://github.com/D3One/Product-Security-Gitbook/blob/main/snippets/ci/github-actions/artifact-attestation.yml)

```yaml
name: attest-build

on:
  push:
    branches: [ main ]

permissions:
  contents: read
  id-token: write
  attestations: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build binary
        run: |
          mkdir -p dist
          echo "example build output" > dist/app.txt
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: app-artifact
          path: dist/app.txt
      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@v1
        with:
          subject-path: dist/app.txt
```

**Verification example**

```bash
gh attestation verify dist/app.txt   --owner your-org
```

**Why Product Security likes it**

* gives provenance for “what was built, where, and by which workflow”;
* supports stronger software supply chain controls;
* pairs well with reusable workflows and deployment policies.

***

## Example 5 - Reusable security workflow used across repositories

**What it does**

Defines one reusable workflow for common security checks, then calls it from many repos.

**Reusable workflow file**

`.github/workflows/reusable-security-gate.yml`

See: [`snippets/ci/github-actions/reusable-security-gate.yml`](https://github.com/D3One/Product-Security-Gitbook/blob/main/snippets/ci/github-actions/reusable-security-gate.yml)

```yaml
name: reusable-security-gate

on:
  workflow_call:
    inputs:
      python-version:
        required: false
        type: string
        default: "3.12"

permissions:
  contents: read
  security-events: write

jobs:
  security-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ inputs.python-version }}
      - name: Run Semgrep
        run: |
          pip install semgrep
          semgrep scan --config p/default .
```

**Calling repo workflow**

```yaml
name: pr-security

on:
  pull_request:
    branches: [ main ]

jobs:
  call-shared-gate:
    uses: your-org/security-standards/.github/workflows/reusable-security-gate.yml@main
    permissions:
      contents: read
      security-events: write
```

**Why it matters**

* avoids copy-paste drift;
* lets Product Security maintain one standard gate;
* works especially well with OIDC and organization-wide rollout.

***

## Other high-value GitHub-native controls

### Secret scanning and push protection

Use the GitHub UI to enable:

* secret scanning;
* push protection;
* validity checks where supported.

**Typical UI path**

* **Repository → Settings → Advanced Security**
* enable **Secret Protection**
* enable **Push protection**

This is not the same as scanning during CI after the secret is already in the repo. Push protection aims to stop the secret before it lands.

### Branch protection + required workflows

A workflow only changes behavior if merge policy depends on it. Mark security workflows as required status checks.

### Environments

Use protected environments for production deployments:

* required reviewers;
* wait timers if justified;
* environment secrets only where absolutely needed.

***

## What used to be common vs what is stronger now

| Older pattern                                  | Why teams used it   | Stronger 2026 pattern                                                |
| ---------------------------------------------- | ------------------- | -------------------------------------------------------------------- |
| store cloud keys in GitHub secrets             | simple              | OIDC federation                                                      |
| every repo owns its own security workflow copy | easy at small scale | reusable workflows and org templates                                 |
| run everything on self-hosted runners          | local control       | split runner trust levels; prefer GitHub-hosted for low-trust checks |
| use Actions only for build/test                | narrow CI mindset   | use Actions as security control plane                                |
| publish artifacts with no provenance           | common legacy flow  | generate and verify attestations                                     |

***

## How Product Security teams use GitHub Actions in practice

### Pattern A - minimum viable security baseline

* dependency review;
* CodeQL or another code scanning layer;
* secret scanning and push protection;
* branch protection with required checks.

### Pattern B - stronger supply chain posture

* SBOM generation;
* artifact attestation;
* signed release workflow;
* OIDC deploy;
* reusable workflows.

### Pattern C - organization-level governance

* centrally maintained reusable workflows;
* enforced dependency review;
* environment protection;
* metrics from alerts, blocked merges, and push-protection events.

***

## Cross-links

* [Signing, Attestation, and Verification — Legacy vs Current](/devsecops-cicd-and-supply-chain/index-1/signing-attestation-and-verification-legacy-vs-current.md)
* [Security Quality Gates and Release Blocking](/devsecops-cicd-and-supply-chain/index-1/security-quality-gates-and-release-blocking.md)
* [Repository Secret Scanning](/application-security-and-secure-sdlc/index-1/repository-secret-scanning.md)
* [Identity and Platform Access](/architecture-api-crypto-and-identity/index-2.md)

***

*Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.product-security.expert/devsecops-cicd-and-supply-chain/index-1/github-actions-for-product-security.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
