GitHub is part of the engineering control plane. It controls source code, CI/CD workflows, secrets, packages, release automation, infrastructure-as-code, and production deployment paths.
This guide is written as an implementation runbook.
For each control, you will see:
- Control objective
- Exact GitHub setting
- What to select
- Validation
- Evidence to retain
Note: Some settings require GitHub Enterprise Cloud, GitHub Advanced Security, or organization owner permissions. If a setting is not visible, confirm your GitHub plan and your permission level.
1. Rollout Order
Use this rollout order. Do not start with advanced scanning before identity, repository governance, and Actions restrictions are under control.
Phase 1 — Identity and organization governance
1. Enforce SSO.
2. Enforce phishing-resistant MFA/passkeys at the IdP.
3. Require GitHub-local MFA/passkeys for direct-auth/fallback accounts, break-glass accounts, outside collaborators, and service accounts where applicable.
4. Require hardware-backed SSH keys for privileged Git push/pull where feasible.
5. Reduce organization owners.
6. Set organization base permissions to No permission.
7. Restrict outside collaborators.
8. Restrict repository creation, deletion, transfer, visibility change, and private forking.
Phase 2 — Repository controls
9. Classify repositories.
10. Create organization ruleset for default branches.
11. Create repo-level rulesets for develop, release/*, and hotfix/* where needed.
12. Add CODEOWNERS for workflows, IaC, deployment, and dependency paths.
13. Add push rulesets for risky file paths and file types where supported.
Phase 3 — CI/CD and supply chain
14. Restrict GitHub Actions to approved actions.
15. Set GITHUB_TOKEN default permissions to read-only.
16. Require explicit workflow permissions.
17. Protect workflow files.
18. Replace long-lived cloud secrets with OIDC.
19. Use GitHub Environments for production deployments.
Phase 4 — Security features, runners, and monitoring
20. Enable secret scanning and push protection.
21. Enable CodeQL/code scanning.
22. Enable Dependabot and dependency review.
23. Secure self-hosted runners.
24. Restrict OAuth Apps, GitHub Apps, PATs, deploy keys, webhooks, and service accounts.
25. Export audit logs or run scheduled audit review.
26. Create a GitHub incident response playbook.
2. Organization Governance and Ownership
Control Objective
Define who owns GitHub security settings, repositories, CI/CD controls, bypasses, exceptions, tokens, runners, and monitoring.
Exact GitHub Setting
GitHub does not provide one single "ownership" setting. Implement ownership using:
Organization → Teams
Repository → Settings → Collaborators and teams
Repository → About → Description / Website / Topics
Organization → Settings → Custom properties, if available
External CMDB / GRC register
What to Do
- Go to
Organization → Teams. - Create or confirm these control-owner teams:
security-admins
security-readonly
platform-admins
devsecops
release-managers
breakglass-admins
- For every repository, define:
Business owner
Technical owner
Repository classification: Critical / High / Medium / Low
Default branch
Production deployment: Yes / No
Uses GitHub Actions: Yes / No
Uses self-hosted runners: Yes / No
Uses cloud deployment credentials: Yes / No
- If GitHub custom properties are available:
Organization → Settings → Custom properties
Create these properties:
business_owner
technical_owner
classification
data_classification
production_deploying_repo
uses_self_hosted_runner
uses_cloud_oidc
exception_required
- Require repository owners to maintain those values.
Required Security Decision
Security owns policy and exceptions.
Platform owns organization guardrails.
Repo owners own repo-level implementation.
Release governance owns production/hotfix bypass approval.
SOC/SecOps owns monitoring and incident triage.
Validation
Review 10 random repositories and confirm each has an owner, classification, and default branch defined.
Evidence to Retain
Team list
Repository ownership register
Custom properties export
Exception approval workflow
Quarterly owner review
3. SSO, Passkeys, and MFA
Control Objective
Use the corporate identity provider as the primary control for GitHub organization access.
Exact GitHub Setting
Organization or Enterprise
→ Settings
→ Authentication security
→ SAML single sign-on
What to Select
Select or configure:
Enable SAML authentication
Enforce SAML single sign-on for the organization
Enable SCIM provisioning, if available
At the identity provider, enforce:
Phishing-resistant MFA / passkeys
Device compliance, if available
Group-based provisioning
Automatic deprovisioning
Step-by-Step Setup
- Go to
Organization → Settings → Authentication security. - Under
SAML single sign-on, configure the IdP metadata. - Test SSO with a non-owner test account.
- Select
Enforce SAML single sign-on. - Configure SCIM provisioning if your plan and IdP support it.
- Map IdP groups to GitHub teams.
- Remove unmanaged users that are not tied to corporate identity.
- Confirm leaver process disables GitHub access through the IdP.
Important Clarification
If SSO uses passkeys or phishing-resistant MFA at the IdP, GitHub-local MFA is not the main control for normal employee access.
Use this standard:
Primary browser access control:
- SSO enforced
- IdP phishing-resistant MFA/passkey enforced
GitHub-local MFA/passkey still required for:
- Break-glass accounts
- Organization owners that can authenticate directly to GitHub
- Outside collaborators
- Service accounts where applicable
- Any account not fully controlled by Enterprise Managed Users
Validation
- Try accessing an organization repo from a member account.
- Confirm GitHub redirects to the IdP.
- Disable a test user in the IdP.
- Confirm the user loses organization access.
- Confirm break-glass accounts have hardware-backed MFA/passkeys.
Evidence to Retain
SSO enforcement screenshot
IdP MFA/passkey policy
SCIM configuration
IdP group-to-GitHub team mapping
Break-glass account register
Access review evidence
4. Hardware-Backed SSH Keys for Git Push/Pull
Control Objective
Protect Git push/pull access from stolen SSH private keys.
Exact GitHub Setting
User-level setting:
User account
→ Settings
→ SSH and GPG keys
→ New SSH key
SSO authorization:
User account
→ Settings
→ SSH and GPG keys
→ Configure SSO
→ Authorize for the organization
Required Security Standard
Privileged users should use YubiKey/FIDO2-backed SSH keys where feasible.
SSH keys must be unique per user.
Shared SSH keys are not allowed.
SSH keys must be authorized for SSO before accessing organization repos.
Inactive users' SSH keys must be removed during offboarding.
Step-by-Step Setup for Users
- Insert the YubiKey or supported hardware security key.
- Generate a FIDO2-backed SSH key:
ssh-keygen -t ed25519-sk -C "user@company.com"
- For a resident/discoverable key, where operationally appropriate:
ssh-keygen -t ed25519-sk -O resident -C "user@company.com"
- Copy the public key:
cat ~/.ssh/id_ed25519_sk.pub
- Go to
GitHub → Settings → SSH and GPG keys → New SSH key. - Paste the public key.
- Save the key.
- Click
Configure SSO. - Click
Authorizefor the organization. - Test access:
ssh -T git@github.com
- Set the repository remote to SSH:
git remote set-url origin git@github.com:ORG/REPO.git
What GitHub Cannot Fully Enforce
GitHub does not provide a simple organization setting that says "only allow YubiKey-backed SSH keys." Enforce this through:
Privileged-user standard
Access reviews
Device/security key rollout
Offboarding process
SSH key audit
Validation
Ask privileged users to show that their SSH keys are -sk backed keys, or collect SSH key inventory through GitHub APIs where available.
Evidence to Retain
SSH key review report
Privileged user hardware-backed SSH attestation
SSO-authorized SSH key evidence
Offboarding removal evidence
5. Reduce Organization Owners
Control Objective
Limit blast radius from privileged GitHub compromise.
Exact GitHub Setting
Organization
→ People
→ Filter by Role: Owner
What to Do
- Go to
Organization → People. - Filter by
Role: Owner. - Remove owner role from anyone who does not need organization-wide administration.
- Use repository
Admin,Maintain, or custom roles instead of org owner for normal repo administration. - Keep a small named break-glass group.
- Set an alert for new organization owner additions.
Required Standard
No shared owner accounts.
No routine engineering work from org-owner accounts.
Org owners reviewed monthly.
Break-glass access reviewed and tested.
Validation
Confirm every org owner has an approved reason.
Evidence to Retain
Org owner export/screenshot
Monthly owner review
Approval for owner additions
Audit log for owner changes
6. Set Base Permission to No Permission
Control Objective
Prevent accidental default access to every repository.
Exact GitHub Setting
Organization
→ Settings
→ Member privileges
→ Base permissions
What to Select
Select:
No permission
Do not select:
Write
Admin
Use Read only if your organization deliberately allows broad internal visibility.
Step-by-Step Setup
- Go to
Organization → Settings. - Open
Member privileges. - Find
Base permissions. - Select
No permission. - Save changes.
- Confirm repository access is granted through teams.
Validation
Pick a normal member not assigned to any team and confirm they do not automatically get repo access.
Evidence to Retain
Base permission setting screenshot
Team access report
Direct access exception list
7. Use Teams for Repository Access
Control Objective
Prevent direct user-to-repository permission sprawl.
Exact GitHub Setting
Organization
→ Teams
Repository access:
Repository
→ Settings
→ Collaborators and teams
What to Do
- Go to
Organization → Teams. - Create teams by application/platform and role.
Recommended pattern:
app-payments-readonly
app-payments-developers
app-payments-maintainers
app-payments-admins
platform-admins
security-readonly
security-admins
release-managers
- Go to each repository.
- Open
Settings → Collaborators and teams. - Add teams, not individual users.
- Remove direct user grants unless they are approved exceptions.
- Map teams to IdP groups if SSO/SCIM supports it.
Permission Guidance
Read: auditors, security read-only, non-contributing stakeholders
Triage: issue/PR triage without code write
Write: active developers
Maintain: repo maintainers without full admin
Admin: small repo admin group only
Validation
Run an access review:
List direct collaborators.
List teams with Admin/Maintain.
Confirm each has owner approval.
Remove stale users and teams.
Evidence to Retain
Team inventory
Repository team access export
Direct collaborator list
Access review sign-off
8. Restrict Outside Collaborators
Control Objective
Control external user access.
Exact GitHub Setting
Organization
→ Settings
→ Member privileges
→ Outside collaborators
What to Configure
- Restrict who can invite outside collaborators.
- Require approval for outside collaborator access.
- Require a sponsor and expiry date.
- Require GitHub-local MFA/passkey.
- Review monthly.
Step-by-Step Setup
- Go to
Organization → Settings → Member privileges. - Locate outside collaborator settings.
- Restrict invitation rights to org owners or approved admins.
- Export current outside collaborators.
- Remove unused or expired users.
- Create an approval workflow requiring:
Sponsor
Business justification
Repository list
Permission level
Expiry date
Data sensitivity
Validation
Review all outside collaborators and confirm each has an active sponsor and expiry date.
Evidence to Retain
Outside collaborator export
Approval tickets
Expiry register
Monthly review evidence
Removal tickets
9. Restrict Repository Creation, Deletion, Transfer, Visibility, and Forking
Control Objective
Prevent uncontrolled repositories, accidental public exposure, and unauthorized transfers.
Exact GitHub Setting
Organization
→ Settings
→ Member privileges
What to Configure
In Member privileges, configure:
Repository creation: Restrict to approved owners/platform teams
Default repository visibility: Private or Internal
Repository deletion: Restrict
Repository transfer: Restrict
Repository visibility changes: Restrict
Private repository forking: Disabled by default
Step-by-Step Setup
- Go to
Organization → Settings → Member privileges. - Find repository creation settings.
- Disable unrestricted member repository creation.
- Set default visibility to
PrivateorInternal. - Restrict repository deletion.
- Restrict repository transfer.
- Restrict visibility changes.
- Disable private repository forking unless there is an approved business need.
- Create a repository onboarding template requiring:
Owner
Classification
Default branch
CODEOWNERS
Ruleset
Security scanning
Actions policy
Secrets review
Validation
Create a test non-admin user and confirm they cannot create/delete/transfer/change visibility unless approved.
Evidence to Retain
Member privilege settings screenshot/export
Repo creation approvals
Visibility change approvals
Public repo approvals
Deletion/transfer approvals
Forking exceptions
10. Repository Classification
Control Objective
Apply stronger controls to repositories that can impact production, data, secrets, cloud infrastructure, or deployments.
Exact GitHub Setting
Use custom properties if available:
Organization
→ Settings
→ Custom properties
Repository view:
Repository
→ Settings
→ General
→ Custom properties, if available
What to Configure
Create custom properties:
classification: Critical / High / Medium / Low
business_owner
technical_owner
data_classification
production_deploying_repo: yes/no
uses_github_actions: yes/no
uses_self_hosted_runner: yes/no
uses_cloud_credentials: yes/no
Step-by-Step Setup
- Go to
Organization → Settings → Custom properties. - Create the properties above.
- Apply them to all repositories.
- Mark these as
Critical:
Production deployment repos
Infrastructure-as-code repos
IAM/security automation repos
Kubernetes/GitOps repos
CI/CD template repos
Payment/authentication/customer-data repos
Package publishing repos
- Require stricter rulesets and reviews for Critical/High repos.
Validation
Export repo list and confirm every repo has classification and owner values.
Evidence to Retain
Repository classification export
Owner mapping
Critical repo list
Control coverage report
11. Organization Ruleset for Default Branch Protection
Control Objective
Protect the source-of-truth branch across all repositories without hard-coding branch names.
Exact GitHub Setting
Organization
→ Settings
→ Rules
→ Rulesets
→ New ruleset
→ New branch ruleset
What to Select
Ruleset name: Org - Default Branch Protection
Target: Branch
Enforcement status: Active
Repository targeting: All repositories, or selected repositories if phased rollout is needed
Branch targeting: Include default branch
Export/API equivalent:
~DEFAULT_BRANCH
Step-by-Step Setup
- Go to
Organization → Settings → Rules → Rulesets. - Click
New ruleset. - Select
New branch ruleset. - Enter name:
Org - Default Branch Protection
- Set
Enforcement statustoActive.
For phased rollout, use Evaluate first, then change to Active after testing.
- Under repository targeting, select:
All repositories
or for rollout:
Only selected repositories
- Under branch targeting, add:
Include default branch
- Do not add these to the global default ruleset unless specifically required:
refs/heads/main
refs/heads/master
refs/heads/develop
refs/heads/hotfix/*
- Enable these rules:
Restrict deletions
Block force pushes / non-fast-forward updates
Require a pull request before merging
Required approvals: 1 minimum
Dismiss stale pull request approvals when new commits are pushed
Require review from Code Owners
Require conversation resolution before merging
Require status checks to pass, where checks exist
Require signed commits, where operationally supported
Require linear history, if using squash/rebase
- Set bypass actors:
Do not add bypass actors by default.
Do not add all repo admins.
Do not add workflow bots.
Do not add broad engineering teams.
- Save the ruleset.
Required Status Checks
For Critical/High repos, require checks such as:
Build
Unit tests
CodeQL / SAST
SCA / dependency scan
Secret scan validation, if implemented as CI
Container scan, if applicable
IaC scan, if applicable
Default Branch Hygiene
Before enforcement, ask repo owners to confirm:
The default branch is correct.
The default branch is the source-of-truth branch.
Deployment and release workflows use the expected branch.
Non-default branches have separate rulesets if needed.
Validation
- Create a test branch.
- Open a PR to the default branch.
- Confirm direct push to default branch is blocked.
- Confirm PR approval is required.
- Confirm CODEOWNER review is required when protected files change.
- Confirm force push and deletion are blocked.
Evidence to Retain
Ruleset export
Target repositories list
Bypass actor list
Required status checks list
Sample blocked direct push
Sample PR showing required approvals and checks
Default branch inventory
12. Repository Rulesets for develop, release/, and hotfix/
Control Objective
Protect non-default operational branches without forcing the same branching model across all repositories.
Exact GitHub Setting
Repository
→ Settings
→ Rules
→ Rulesets
→ New ruleset
→ New branch ruleset
Branch Ruleset Decision
| Branch | Level | Use |
|---|---|---|
| Default branch | Organization ruleset | Applies to all repos |
| develop | Repository-level or repo-scoped org ruleset | Only where develop is used |
| release/* | Repository-level or repo-scoped org ruleset | Only where release branches are used |
| hotfix/* | Repository-level or repo-scoped org ruleset | Only where emergency hotfix branches are used |
12.1 develop Branch Ruleset
What to Select
Ruleset name: Repo - Develop Branch Protection
Target: Branch
Enforcement status: Active
Branch targeting: refs/heads/develop
Step-by-Step Setup
- Go to
Repository → Settings → Rules → Rulesets. - Click
New ruleset. - Select
New branch ruleset. - Name it:
Repo - Develop Branch Protection
- Set enforcement to
Active. - Under branch targeting, add:
refs/heads/develop
- Enable:
Restrict deletions
Block force pushes
Require a pull request before merging
Required approvals: 1
Dismiss stale approvals
Require conversation resolution
Require status checks, where applicable
Require CODEOWNER review for Critical/High repos
- Optional, only if workflow supports it:
Require signed commits
Require linear history
- Do not add broad bypass actors.
Validation
Try direct push to develop. It should be blocked.
Evidence to Retain
Develop ruleset export
Required check list
Bypass actor list
Exception record if bypass exists
12.2 release/* Branch Ruleset
What to Select
Ruleset name: Repo - Release Branch Protection
Target: Branch
Enforcement status: Active
Branch targeting: refs/heads/release/*
Step-by-Step Setup
- Go to
Repository → Settings → Rules → Rulesets. - Click
New branch ruleset. - Name it:
Repo - Release Branch Protection
- Set enforcement to
Active. - Add branch pattern:
refs/heads/release/*
- Enable:
Restrict deletions
Block force pushes by default
Require a pull request before merging
Required approvals: 1 or 2 for Critical repos
Dismiss stale approvals
Require conversation resolution
Require status checks
Require CODEOWNER review for sensitive paths
- Add required checks:
Build
Unit tests
Integration tests
CodeQL / SAST
SCA / dependency scan
Container scan, if applicable
IaC scan, if applicable
Release dry run, if applicable
- Bypass actors must be limited to:
Approved release managers
Approved platform admins
Approved security/release break-glass actors
- Do not give every repo admin release bypass by default.
Validation
Open a PR into release/test. Confirm approvals and checks are required.
Evidence to Retain
Release ruleset export
Release manager list
Bypass approval
Required checks evidence
Release change ticket
12.3 hotfix/* Branch Ruleset
What to Select
Ruleset name: Repo - Hotfix Branch Protection
Target: Branch
Enforcement status: Active
Branch targeting: refs/heads/hotfix/*
Step-by-Step Setup
- Go to
Repository → Settings → Rules → Rulesets. - Click
New branch ruleset. - Name it:
Repo - Hotfix Branch Protection
- Set enforcement to
Active. - Add branch pattern:
refs/heads/hotfix/*
- Enable:
Restrict deletions
Block force pushes by default
Require a pull request where feasible
Required approvals: 1
Require status checks where feasible
Require conversation resolution where feasible
Require CODEOWNER review for sensitive paths
- Configure bypass only if emergency force-push is truly required.
Hotfix Bypass Model
Use this ownership model:
Repo admin / engineering owner:
- Implements and maintains the hotfix ruleset.
Security / Release Governance:
- Approves bypass model and bypass actors.
Approved break-glass users:
- Execute emergency bypass only when justified, logged, and reviewed.
What Not to Do
Do not add all repo admins as always-bypass.
Do not add a workflow bot as global bypass.
Do not allow developer teams to self-approve bypass.
Do not leave emergency bypass without expiry/review.
Validation
Run a hotfix tabletop:
Create hotfix branch.
Attempt direct force push.
Confirm blocked.
Create emergency bypass request.
Confirm approval path.
Confirm audit log captures bypass.
Confirm post-use review occurs.
Evidence to Retain
Hotfix ruleset export
Break-glass approver list
Emergency change ticket
Audit log for bypass use
Post-hotfix review
13. Push Rulesets for High-Risk Files
Control Objective
Block risky files from being pushed to private/internal repositories and their fork network where supported.
Exact GitHub Setting
Organization
→ Settings
→ Rules
→ Rulesets
→ New ruleset
→ New push ruleset
Repository-level:
Repository
→ Settings
→ Rules
→ Rulesets
→ New push ruleset
What to Configure
Use push rulesets to block known risky file paths, extensions, and large files where supported.
Recommended blocked patterns:
.env
.env.*
*.pem
*.key
*.p12
*.pfx
id_rsa
id_dsa
id_ecdsa
id_ed25519
**/secrets/**
**/private/**
*.tfstate
*.tfstate.*
Step-by-Step Setup
- Go to
Organization → Settings → Rules → Rulesets. - Click
New ruleset. - Select
New push ruleset. - Name it:
Org - High Risk File Push Protection
- Set enforcement to
Evaluatefirst. - Target private/internal repositories.
- Add file path or extension restrictions.
- Review violations for false positives.
- Change enforcement to
Active.
Validation
Attempt to push a test file such as:
test.pem
.env.test
The push should be blocked once active.
Evidence to Retain
Push ruleset export
Blocked pattern list
Violation logs
Exception list
14. CODEOWNERS for Sensitive Paths
Control Objective
Require the correct owners to approve changes to CI/CD, infrastructure, deployment, and dependency files.
Exact GitHub Setting
Create a CODEOWNERS file:
Repository
→ Add file
→ Create new file
→ .github/CODEOWNERS
Then enforce it through:
Organization or repository ruleset
→ Require review from Code Owners
Step-by-Step Setup
- In the repository, create:
.github/CODEOWNERS
- Add owners for sensitive paths:
# GitHub workflow control plane
.github/workflows/** @org/platform-security @org/devsecops
.github/actions/** @org/platform-security @org/devsecops
# Infrastructure as Code
terraform/** @org/cloud-platform @org/security
terragrunt/** @org/cloud-platform @org/security
cloudformation/** @org/cloud-platform @org/security
# Kubernetes and deployment
k8s/** @org/platform-engineering @org/security
helm/** @org/platform-engineering @org/security
argocd/** @org/platform-engineering @org/security
deploy/** @org/platform-engineering @org/security
scripts/deploy/** @org/platform-engineering @org/security
# Container and build files
Dockerfile @org/appsec
docker/** @org/appsec
# Dependencies
package.json @org/appsec
package-lock.json @org/appsec
yarn.lock @org/appsec
pnpm-lock.yaml @org/appsec
Gemfile @org/appsec
Gemfile.lock @org/appsec
pom.xml @org/appsec
build.gradle @org/appsec
requirements.txt @org/appsec
go.mod @org/appsec
go.sum @org/appsec
- Commit the file through PR.
- Ensure the branch/ruleset has
Require review from Code Ownersenabled. - Test with a PR modifying
.github/workflows/test.yml.
Validation
A PR modifying a protected path should require the listed CODEOWNER team.
Evidence to Retain
CODEOWNERS file
Ruleset with CODEOWNER review enabled
Test PR showing CODEOWNER requirement
Quarterly CODEOWNERS review
15. GitHub Actions Organization Policy
Control Objective
Prevent unreviewed third-party code from running in CI/CD.
Exact GitHub Setting
Organization
→ Settings
→ Actions
→ General
What to Select
Under Policies, configure:
Allow GitHub Actions to run: Enabled only where needed
Actions permissions: Allow selected actions and reusable workflows
Preferred policy:
Allow actions created by GitHub
Allow Marketplace verified creators only if your risk tolerance allows it
Allow specified actions and reusable workflows
Block all other public actions
If using enterprise-owned internal actions, allow:
Actions and reusable workflows in your enterprise or organization
Step-by-Step Setup
- Go to
Organization → Settings → Actions → General. - Under
Actions permissions, do not selectAllow all actions and reusable workflows. - Select the most restrictive option available, usually:
Allow selected actions and reusable workflows
- Allow GitHub-owned actions if required.
- In the allowlist, add approved actions only.
Example allowlist:
actions/checkout@v4
actions/setup-node@v4
actions/setup-python@v5
ruby/setup-ruby@v1
github/codeql-action/*
aws-actions/configure-aws-credentials@v4
For third-party community actions, prefer exact version or SHA:
kentaro-m/auto-assign-action@v2.0.2
madrapps/jacoco-report@v1.7.2
For high-risk workflows, require full commit SHA.
Do Not Allow
*@*
owner/*
third-party/action@*
unreviewed/action@main
unreviewed/action@master
Required Review Before Approving an Action
Before adding a third-party action to the allowlist, check:
Maintainer reputation
Recent commits/releases
Open issues mentioning compromise
Required permissions
Whether it runs arbitrary scripts
Whether it handles secrets
Whether it writes to PRs, issues, packages, releases, or workflows
Whether SHA pinning is required
Validation
Create a test workflow using an unapproved action. It should fail with an Actions policy error.
Evidence to Retain
Organization Actions policy screenshot/export
Approved actions register
Rejected action test result
Action approval tickets
16. GITHUB_TOKEN Workflow Permissions
Control Objective
Reduce blast radius from compromised workflows or malicious Actions.
Exact GitHub Setting
Organization
→ Settings
→ Actions
→ General
→ Workflow permissions
Repository override, if needed:
Repository
→ Settings
→ Actions
→ General
→ Workflow permissions
What to Select
Select:
Read repository contents and packages permissions
Uncheck or disable where possible:
Allow GitHub Actions to create and approve pull requests
Step-by-Step Setup
- Go to
Organization → Settings → Actions → General. - Scroll to
Workflow permissions. - Select:
Read repository contents and packages permissions
- Do not select:
Read and write permissions
unless required by exception.
- Disable:
Allow GitHub Actions to create and approve pull requests
unless explicitly approved.
- Require every workflow to declare
permissions:.
Secure default:
permissions:
contents: read
PR comment workflow:
permissions:
contents: read
pull-requests: write
issues: write
Cloud OIDC workflow:
permissions:
contents: read
id-token: write
Do not allow:
permissions: write-all
Validation
Scan workflows for:
permissions: write-all
contents: write
actions: write
id-token: write
secrets write/admin permissions
Every write permission should have justification.
Evidence to Retain
Workflow permission setting screenshot
Workflow permissions inventory
Approved write-permission exceptions
17. Protect Workflow Files
Control Objective
Prevent unauthorized CI/CD logic changes.
Exact GitHub Setting
Use CODEOWNERS and rulesets.
CODEOWNERS file:
.github/CODEOWNERS
Protected paths:
.github/workflows/**
.github/actions/**
Ruleset:
Require review from Code Owners
Step-by-Step Setup
- Add CODEOWNERS:
.github/workflows/** @org/platform-security @org/devsecops
.github/actions/** @org/platform-security @org/devsecops
- Enable CODEOWNER review in default branch ruleset.
- Require PR before merge.
- Require status checks where available.
- Review any workflow change for:
New or changed third-party actions
New write permissions
New id-token: write
New secrets
New self-hosted runner labels
pull_request_target
workflow_run
repository_dispatch
release/package publishing
Validation
Open a PR changing .github/workflows/build.yml. It must require platform/security CODEOWNER review.
Evidence to Retain
CODEOWNERS file
Workflow change PR approval
Workflow review checklist
18. OIDC for Cloud Deployments
Control Objective
Remove long-lived AWS/Azure/GCP credentials from GitHub secrets.
GitHub Setting
Repository
→ Settings
→ Secrets and variables
→ Actions
Cloud side:
AWS IAM / Azure Entra ID / GCP IAM
→ OIDC trust configuration
What to Do
Replace static cloud keys with GitHub OIDC.
AWS Step-by-Step Setup
- In AWS IAM, create or confirm an OIDC provider for:
https://token.actions.githubusercontent.com
- Create an IAM role for GitHub deployment.
- Scope the trust policy tightly.
Example trust condition:
{
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:ORG/REPO:environment:production"
}
}
}
- In GitHub, create an environment:
Repository → Settings → Environments → production
- Require reviewers for production.
- Update workflow:
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-prod-deploy
aws-region: ap-southeast-1
- Remove static AWS keys from GitHub secrets after migration.
Required OIDC Scope
Use at least one of:
repo:ORG/REPO:environment:production
repo:ORG/REPO:ref:refs/heads/main
repo:ORG/REPO:ref:refs/heads/release/*
Do not allow:
repo:ORG/*
*
Validation
- Run deployment workflow.
- Confirm it assumes the AWS role via OIDC.
- Confirm static cloud secrets are removed.
- Confirm another repo/branch cannot assume the role.
Evidence to Retain
AWS IAM trust policy
GitHub workflow file
GitHub environment configuration
CloudTrail AssumeRoleWithWebIdentity event
Removed static secret evidence
19. GitHub Environments for Production
Control Objective
Separate code merge permission from production deployment permission.
Exact GitHub Setting
Repository
→ Settings
→ Environments
→ New environment
What to Select
For production:
Environment name: production
Required reviewers: Enabled
Prevent self-review: Enabled, if available
Deployment branches and tags: Selected branches and tags
Environment secrets: Production-only
Admin bypass: Disabled or tightly restricted, if available
Step-by-Step Setup
- Go to
Repository → Settings → Environments. - Click
New environment. - Name it:
production
- Enable
Required reviewers. - Add release managers or platform/security approvers.
- Enable
Prevent self-reviewif available. - Under deployment branches/tags, select:
Selected branches and tags
- Add allowed patterns:
main
release/*
hotfix/*
v*
- Add production secrets only at the environment level.
- Update workflows to use:
environment: production
Validation
Trigger a production deployment. GitHub should pause for environment approval.
Evidence to Retain
Environment configuration screenshot
Reviewer list
Deployment approval logs
Environment secrets inventory
20. Secret Scanning and Push Protection
Control Objective
Detect and block secrets before they enter repositories.
Exact GitHub Setting
Organization level, if available:
Organization
→ Settings
→ Code security and analysis
Repository level:
Repository
→ Settings
→ Code security and analysis
What to Enable
Enable:
Secret scanning
Push protection
Validity checks, if available
Non-provider patterns, if available
Custom patterns for internal secrets
Step-by-Step Setup
- Go to
Organization → Settings → Code security and analysis. - Enable
Secret scanning. - Enable
Push protection. - Add custom patterns for internal secrets.
- Apply to all repositories where available.
- For any repo that does not inherit org settings, go to
Repository → Settings → Code security and analysisand enable there.
Custom patterns to add:
Internal API keys
Private registry tokens
Service account tokens
Database credentials
Legacy cloud keys
Webhook signing secrets
Internal JWT signing secrets
Secret Alert Response
For every real secret alert:
1. Revoke or rotate the secret immediately.
2. Review logs for abuse.
3. Remove the secret from active code.
4. Decide whether history cleanup is required.
5. Add prevention control.
6. Close the alert with evidence.
Validation
Attempt to push a known test secret pattern in a test repo. Push protection should block it.
Evidence to Retain
Secret scanning setting
Push protection setting
Custom pattern list
Secret alert tickets
Rotation evidence
21. CodeQL / Code Scanning
Control Objective
Find insecure code before production release.
Exact GitHub Setting
Repository:
Repository
→ Security
→ Code scanning
→ Set up code scanning
or:
Repository
→ Settings
→ Code security and analysis
→ Code scanning
Organization-level security configurations, if available:
Organization
→ Settings
→ Code security and analysis
→ Configurations
What to Enable
For supported languages:
CodeQL default setup
For custom build/language needs:
CodeQL advanced setup
Step-by-Step Setup
- Go to the repository.
- Open
Security → Code scanning. - Click
Set up code scanning. - Select
CodeQL. - Use
Default setupwhere supported. - If build customization is needed, choose
Advanced setup. - Confirm a CodeQL workflow is created.
- Go to the default branch ruleset.
- Add CodeQL/code scanning as a required status check for Critical/High repos.
Required Severity Handling
Critical: Block release or approved exception required.
High: Fix before production release or within SLA.
Medium: Assign owner and backlog.
Low/Informational: Triage and tune if noisy.
Validation
Confirm Security → Code scanning alerts shows results after a workflow run.
Evidence to Retain
Code scanning configuration
CodeQL workflow
Required check list
Alert dashboard
Remediation tickets
22. Dependabot, Dependency Review, and SBOM
Control Objective
Reduce vulnerable dependency and supply-chain risk.
Exact GitHub Setting
Repository
→ Settings
→ Code security and analysis
What to Enable
Enable:
Dependency graph
Dependabot alerts
Dependabot security updates
Dependency review
Step-by-Step Setup
- Go to
Repository → Settings → Code security and analysis. - Enable
Dependency graph. - Enable
Dependabot alerts. - Enable
Dependabot security updates. - Enable
Dependency review, if available. - Add
.github/dependabot.yml.
Example:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "bundler"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- For Critical/High repos, require dependency review as a status check.
Validation
Confirm Dependabot creates alerts or security PRs when vulnerable dependencies exist.
Evidence to Retain
Dependabot settings
Dependabot PRs
Dependency alert list
Dependency review check
SBOM artifact, if generated
23. Release, Tag, Package, and Artifact Security
Control Objective
Protect releases, tags, packages, and artifacts from unauthorized modification.
Exact GitHub Settings
Tag ruleset:
Repository or Organization
→ Settings
→ Rules
→ Rulesets
→ New tag ruleset
Packages:
Repository or Organization
→ Packages
Environments:
Repository
→ Settings
→ Environments
What to Configure
Create a tag ruleset.
Ruleset name: Release Tag Protection
Target: Tag
Tag pattern: v*
Enforcement: Active
Enable:
Restrict deletions
Block force updates
Require signed tags, where operationally supported
Restrict who can create/update/delete matching tags
For package publishing workflows:
Limit packages: write permission
Require environment approval for production publishing
Use OIDC where supported
Use artifact attestation/provenance where available
Step-by-Step Setup
- Go to
Repository → Settings → Rules → Rulesets. - Click
New ruleset. - Select
New tag ruleset. - Target:
v*
- Enable deletion/update protections.
- Restrict creation/update to release managers or release workflow.
- Review workflows that publish packages.
- Limit workflow token permissions:
permissions:
contents: read
packages: write
id-token: write
Only include packages: write in jobs that publish packages.
Validation
Try deleting or moving a protected release tag as a non-approved user. It should fail.
Evidence to Retain
Tag ruleset export
Release workflow
Package permissions
Release approval logs
Artifact attestation/provenance
24. Personal Access Tokens, Fine-Grained Tokens, and Service Accounts
Control Objective
Prevent unmanaged tokens from accessing organization repositories and APIs.
Exact GitHub Setting
Organization
→ Settings
→ Personal access tokens
→ Settings
Review:
Fine-grained tokens
Tokens (classic)
Fine-Grained PATs — What to Select
Select:
Require administrator approval
Set maximum lifetime if available:
90 days for normal use
30 days for high-risk use
7 days for temporary troubleshooting
Classic PATs — What to Select
Select the most restrictive available option:
Restrict access via personal access tokens (classic)
or equivalent setting that prevents classic PATs from accessing organization resources by default.
Step-by-Step Setup
- Go to
Organization → Settings → Personal access tokens → Settings. - Open
Fine-grained tokens. - Select
Require administrator approval. - Configure maximum token lifetime where available.
- Open
Tokens (classic). - Restrict classic PAT access to organization resources.
- Review existing token access.
- Revoke unused, broad, or orphaned tokens.
- Migrate automations to GitHub Apps, OIDC,
GITHUB_TOKEN, or fine-grained PATs. - Require exception approval for any classic PAT.
Fine-Grained PAT Approval Criteria
Approve only if:
Selected repositories only
Minimum permissions only
Expiry set
Named owner
Business justification
Storage location documented
Repo owner approval for write access
Security approval for workflow/admin/org permissions
Do Not Approve
No-expiry tokens
Classic PATs with broad repo scope
Tokens owned by former employees
Tokens stored on laptops/runners
Tokens with workflow/admin/org permissions without Security approval
Validation
Submit a test fine-grained PAT request for org access. It should require administrator approval.
Evidence to Retain
PAT policy screenshot/export
Fine-grained PAT approval list
Classic PAT exception list
Revoked token list
Token review report
Service account register
25. OAuth Apps, GitHub Apps, Deploy Keys, and Webhooks
Control Objective
Prevent unmanaged integrations from accessing organization data or triggering automation.
Exact GitHub Settings
OAuth Apps:
Organization
→ Settings
→ Third-party access
→ OAuth app access restrictions
GitHub Apps:
Organization
→ Settings
→ GitHub Apps
Deploy keys:
Repository
→ Settings
→ Deploy keys
Webhooks:
Repository
→ Settings
→ Webhooks
What to Configure
OAuth Apps:
Restrict third-party application access
Require approval before organization access
GitHub Apps:
Approve only required permissions
Install only on selected repositories
Avoid organization-wide installation unless justified
Deploy keys:
Remove unused deploy keys
Avoid write-enabled deploy keys
Require owner and justification
Webhooks:
Require HTTPS
Require webhook secret
Validate target ownership
Review event subscriptions
Step-by-Step Setup
- Go to
Organization → Settings → Third-party access. - Enable OAuth App access restrictions.
- Review approved OAuth Apps.
- Remove unused or over-scoped apps.
- Go to
Organization → Settings → GitHub Apps. - Review installed GitHub Apps.
- Confirm each app has owner, purpose, repo scope, and permission scope.
- Go to each Critical/High repo.
- Review
Deploy keysandWebhooks. - Remove unused keys/hooks.
- Add webhook secrets where missing.
Validation
Pick five installed apps and confirm each has least privilege and selected repository scope.
Evidence to Retain
OAuth App inventory
GitHub App inventory
Deploy key list
Webhook list
Permission review
Quarterly review record
26. Self-Hosted Runner Security
Control Objective
Prevent GitHub Actions jobs from becoming a pivot into internal infrastructure or production systems.
Exact GitHub Setting
Organization
→ Settings
→ Actions
→ Runners
→ Runner groups
Repository-level runner view:
Repository
→ Settings
→ Actions
→ Runners
Required Runner Groups
Create separate runner groups:
runner-public-low-trust
runner-internal-build
runner-internal-test
runner-production-deploy
runner-security-tools
Step-by-Step Setup
- Go to
Organization → Settings → Actions → Runners. - Click
Runner groups. - Create
runner-internal-build. - Restrict it to selected internal repositories.
- Create
runner-production-deploy. - Restrict it to production deployment repositories only.
- Do not allow public repositories to use privileged self-hosted runners.
- Do not allow sandbox or experimental repos to use production runners.
- Prefer ephemeral or just-in-time runners for production deployment jobs.
- Install EDR/host monitoring on runner hosts.
- Restrict runner network egress.
Runner Group Access Standard
Production runners:
- Only production deployment repos
- No public repos
- No fork PRs
- No sandbox repos
- No broad internal network access
Build runners:
- Internal build repos only
- No production secrets
- Limited network egress
Security runners:
- Security-owned repos only
- Separate credentials
- Monitored heavily
Block Dangerous Workflow Patterns
Review workflows using:
pull_request_target
workflow_run
repository_dispatch
self-hosted runner labels on PR workflows
secrets exposed to PR workflows
Host Hardening
Apply:
Patch runner OS regularly
Run runner service as dedicated low-privilege user
Do not run as root/admin unless justified
Clean workspace after jobs
Do not store long-lived credentials locally
Restrict interactive login
Install EDR
Enable network logs
Use separate hosts for separate trust zones
Network Controls
Restrict outbound access to:
GitHub
Required package registries
Artifact repository
Cloud deployment endpoints
Required internal services only
Block or restrict:
Broad internal RFC1918 access
Cloud metadata access where possible
Production databases unless explicitly required
Lateral movement paths
Validation
- Confirm a sandbox repo cannot target
runner-production-deploy. - Confirm public repos cannot use privileged runners.
- Confirm fork PR workflows do not run on privileged self-hosted runners.
- Confirm production runner has limited network access.
Evidence to Retain
Runner group configuration
Allowed repository list per runner group
Runner host hardening checklist
EDR coverage report
Network rules
Runner job logs
Runner group access review
27. Repository Forking and Pull Request Safety
Control Objective
Prevent untrusted fork workflows from accessing secrets, write tokens, or privileged runners.
Exact GitHub Settings
Organization:
Organization
→ Settings
→ Member privileges
→ Repository forking
Repository:
Repository
→ Settings
→ Actions
→ General
What to Configure
Private repository forking: Disabled by default
Fork pull request workflows: Require approval where available
Secrets to fork PRs: Do not expose
Privileged self-hosted runners: Do not allow for fork PRs
Step-by-Step Setup
- Go to
Organization → Settings → Member privileges. - Disable private repository forking unless approved.
- For public repos, go to
Repository → Settings → Actions → General. - Require approval for workflows from outside collaborators/forks where available.
- Review all workflows using
pull_request_target. - Do not checkout untrusted fork code in privileged contexts.
- Do not use self-hosted privileged runners for fork PR workflows.
Validation
Open a fork PR and confirm secrets and privileged runners are not available.
Evidence to Retain
Forking policy screenshot
Fork workflow approval setting
pull_request_target workflow review
Runner access review
28. Audit Logs and Monitoring
Control Objective
Detect high-risk GitHub changes and support investigations.
Exact GitHub Setting
Audit log:
Enterprise or Organization
→ Settings
→ Audit log
Log streaming, where available:
Enterprise
→ Settings
→ Audit log
→ Log streaming
What to Configure
Enable audit log streaming to SIEM/log lake where available
If streaming is unavailable, schedule audit log export/review
Create alerts for high-risk GitHub events
Events to Alert On
Organization owner added
SSO enforcement changed
MFA/passkey requirement changed
Repository made public
Repository transferred
Repository deleted
Ruleset changed
Ruleset bypass actor added
Branch protection disabled
Secret scanning disabled
Push protection disabled
GitHub Actions policy changed
Workflow file changed
Self-hosted runner added
Runner group changed
OAuth App approved
GitHub App installed
PAT policy changed
Fine-grained PAT approved
Classic PAT exception created
Production environment reviewer removed
Deployment secret changed
Release or tag modified unexpectedly
Step-by-Step Setup
- Go to
Enterprise or Organization → Settings → Audit log. - Configure streaming if available.
- Send logs to SIEM.
- Build detections for the events above.
- Create a weekly review process if streaming is not available.
- Assign SOC/SecOps ownership for triage.
Validation
Make a low-risk test change, such as adding/removing a test runner group or modifying a test ruleset. Confirm the event reaches SIEM.
Evidence to Retain
Audit log streaming configuration
SIEM ingestion proof
Detection rules
Alert tickets
Scheduled review records
29. GitHub Incident Response Playbook
Control Objective
Prepare for GitHub compromise, token leakage, malicious workflow changes, and release tampering.
Required Playbooks
Create response steps for:
Compromised developer account
Compromised organization owner
Leaked secret
Malicious workflow change
Malicious GitHub Action
Compromised self-hosted runner
Unauthorized repository visibility change
Malicious release or tag
Unauthorized production deployment
Compromised PAT or OAuth App
Suspicious repo clone or mass download
Containment Actions
Suspend user
Revoke PAT/fine-grained token
Remove OAuth/GitHub App access
Disable workflow
Rotate secrets
Revoke cloud OIDC trust or cloud role access
Disable deployment environment
Remove runner from runner group
Block compromised runner host
Revert malicious commits
Lock affected branches
Archive evidence
Evidence to Preserve
Audit logs
Workflow run logs
PR history
Commit history
Release/tag metadata
Deployment logs
Runner logs
Secret scanning alerts
Cloud access logs
Package publish logs
Token approval/revocation logs
Validation
Run one tabletop exercise per year covering:
Leaked production secret
Malicious workflow change
Compromised GitHub App/PAT
Compromised self-hosted runner
Evidence to Retain
GitHub IR playbook
Tabletop report
Incident ticket
Timeline
Containment log
Post-incident review
Control improvement plan
30. Exception and Bypass Governance
Control Objective
Prevent security exceptions from becoming permanent hidden risk.
Required Action
Every exception must be approved, time-bound, owned, logged, and reviewed.
Required Exception Fields
Control being bypassed
Repository or organization scope
Business justification
Risk impact
Requested actor/team/app
Requested permission
Start date
Expiry date
Compensating controls
Approver
Review cadence
Rollback plan
Bypass Rules
No permanent broad bypass by default.
No workflow bot global bypass by default.
No repo-admin self-approved bypass for production-impacting branches.
Security or release governance approves bypass actors for hotfix and production workflows.
All bypass use must be logged and reviewed after use.
Exact GitHub Locations to Review Bypass
Rulesets:
Organization or Repository
→ Settings
→ Rules
→ Rulesets
→ Select ruleset
→ Bypass list / Bypass actors
Environments:
Repository
→ Settings
→ Environments
→ production
→ Deployment protection / reviewers / admin bypass
Actions:
Organization
→ Settings
→ Actions
→ General
Validation
Review all bypass actors monthly and remove stale entries.
Evidence to Retain
Exception tickets
Risk acceptances
Bypass actor export
Audit logs
Expiry review
Closure evidence
31. Minimum Secure GitHub Baseline Checklist
Identity and Access
[ ] SSO enforced
[ ] IdP phishing-resistant MFA/passkeys enforced
[ ] GitHub-local MFA/passkeys required for direct-auth/fallback accounts, break-glass accounts, outside collaborators, and service accounts where applicable
[ ] Hardware-backed SSH keys required where feasible for privileged Git push/pull
[ ] SSH keys and tokens authorized for SSO where required
[ ] Org owners minimized
[ ] Org owners reviewed monthly
[ ] Base permission set to No permission
[ ] Team-based access implemented
[ ] Direct user-to-repo access minimized
[ ] Outside collaborators restricted and reviewed
Organization Governance
[ ] Repo creation restricted
[ ] Repo deletion restricted
[ ] Repo transfer restricted
[ ] Visibility changes restricted
[ ] Private repo forking disabled by default
[ ] Repository classification completed
[ ] Repository owners assigned
Branch, Tag, and Push Rulesets
[ ] Org ruleset protects default branch
[ ] Default branch hygiene validated
[ ] PR required before merge
[ ] Approval required
[ ] CODEOWNER review required for Critical repos
[ ] Stale reviews dismissed
[ ] Conversation resolution required
[ ] Required status checks configured
[ ] Force push blocked
[ ] Branch deletion blocked
[ ] Bypass actors minimized
[ ] Repo-level develop/release/hotfix rulesets created where needed
[ ] Release tag ruleset created where needed
[ ] Push ruleset blocks risky file types/paths where supported
CODEOWNERS
[ ] .github/workflows/** protected
[ ] .github/actions/** protected
[ ] IaC paths protected
[ ] Kubernetes/deployment paths protected
[ ] Package/dependency files protected
[ ] CODEOWNERS reviewed quarterly
GitHub Actions
[ ] Actions restricted to approved sources
[ ] No third-party @* approvals
[ ] High-risk Actions pinned to full SHA
[ ] Default GITHUB_TOKEN read-only
[ ] Explicit workflow permissions required
[ ] write-all prohibited unless approved
[ ] pull_request_target workflows reviewed
[ ] Workflow changes require CODEOWNER review
Secrets and Cloud Access
[ ] Secret scanning enabled
[ ] Push protection enabled
[ ] Custom secret patterns configured
[ ] Static cloud keys removed where possible
[ ] OIDC configured for cloud deployments
[ ] Production environments protected
[ ] Production secrets scoped to environments
Application and Dependency Security
[ ] Code scanning enabled
[ ] Code scanning required checks configured for Critical/High repos
[ ] Dependabot alerts enabled
[ ] Dependabot security updates enabled
[ ] Dependency review enabled
[ ] Critical/high findings tracked to closure
[ ] SBOM generated for Critical/High production services where feasible
Runners
[ ] Runner groups segmented by trust level
[ ] Privileged runners restricted to approved repos
[ ] Untrusted fork PRs blocked from privileged runners
[ ] Ephemeral runners used where feasible
[ ] Runner network access restricted
[ ] Runner hosts hardened and monitored
Tokens and Integrations
[ ] Classic PATs restricted
[ ] Fine-grained PATs require approval
[ ] Token maximum lifetime configured where available
[ ] Service accounts inventoried and reviewed
[ ] OAuth Apps reviewed
[ ] GitHub Apps reviewed
[ ] Deploy keys reviewed
[ ] Webhooks reviewed and protected with secrets
Release and Package Security
[ ] Release branches protected
[ ] Release tags protected
[ ] Package publishing restricted
[ ] Artifact provenance/attestation used where available
[ ] Release approvals logged
Monitoring and IR
[ ] Audit logs exported or reviewed
[ ] High-risk events monitored
[ ] GitHub IR playbook created
[ ] Exceptions are time-bound and reviewed
[ ] Bypass usage reviewed after each use
32. Repository Rollout Ticket Template
Title:
Implement GitHub security baseline for <repo/org>
Scope:
<organization or repository name>
Repository classification:
Critical / High / Medium / Low
Exact actions:
[ ] Confirm business owner
[ ] Confirm technical owner
[ ] Confirm default branch
[ ] Confirm repository classification
[ ] Confirm production deployment status
[ ] Apply org default branch ruleset
[ ] Add repo-level develop ruleset if used
[ ] Add repo-level release/* ruleset if used
[ ] Add repo-level hotfix/* ruleset if used
[ ] Add release tag ruleset if repo creates releases
[ ] Add push ruleset for risky file types/paths if supported
[ ] Add CODEOWNERS for workflows, IaC, deployment, dependencies
[ ] Enable secret scanning
[ ] Enable push protection
[ ] Enable CodeQL/code scanning
[ ] Enable Dependabot alerts
[ ] Enable Dependabot security updates
[ ] Enable dependency review
[ ] Review workflows for permissions
[ ] Remove unapproved Actions
[ ] Set explicit workflow permissions
[ ] Replace cloud secrets with OIDC where possible
[ ] Configure GitHub Environment for production
[ ] Review PATs, deploy keys, GitHub Apps, OAuth Apps, and webhooks
[ ] Review runner usage and runner group access
[ ] Confirm audit monitoring
Evidence required:
- Ruleset export
- CODEOWNERS file
- Code security settings screenshot/export
- Actions policy compliance evidence
- Workflow permission review
- Approved Actions list
- Secrets/token review
- Runner group review
- Environment approval settings
- Exception records
Approvers:
Engineering owner:
Platform owner:
Security owner:
Release owner, if production:
Due date:
33. Final Operating Standard
GitHub security should be implemented as enforceable settings, not informal advice.
The minimum operating standard is:
SSO enforced.
IdP passkeys/phishing-resistant MFA enforced.
Hardware-backed SSH for privileged Git access where feasible.
Org owners minimized.
Base permissions set to No permission.
Default branch protected by org ruleset.
develop/release/hotfix protected only where used.
CODEOWNERS required for workflow/IaC/deployment paths.
GitHub Actions restricted to approved actions.
GITHUB_TOKEN read-only by default.
Workflow permissions explicit.
Static cloud keys replaced with OIDC.
Production deployments protected by environments.
Secret scanning and push protection enabled.
Code scanning and Dependabot enabled.
Self-hosted runners isolated by trust level.
PATs, apps, deploy keys, and webhooks governed.
Audit logs monitored.
Exceptions time-bound and reviewed.
The goal is not to slow engineering down. The goal is to remove unsafe paths while keeping normal development predictable, auditable, and secure.
Top comments (0)