The full GitHub security stack — Dependabot alerts vs security updates vs version updates, dependabot.yml configuration, secret scanning with push protection, dependency review in PRs, security advisories, and minimising blast radius with scoped secrets
GitHub's security tooling covers four distinct threat categories. Understanding which feature addresses which threat is the starting point for building a coherent security posture.
Dependabot alertsThreat: known vulnerabilities in your dependencies. GitHub compares your dependency graph against the GitHub Advisory Database (GHSA) and alerts when a match is found. Passive — alerts you, doesn't fix anything.
Dependabot security updatesThreat: same as above. GitHub automatically opens a PR that bumps the vulnerable dependency to a non-vulnerable version. Reactive — responds to newly published CVEs.
Dependabot version updatesThreat: dependency staleness and future vulnerability exposure. Proactively opens PRs to keep dependencies current on a schedule. Configured in dependabot.yml.
Secret scanningThreat: accidentally committed credentials (API keys, tokens, passwords). Scans every push and every historical commit for known secret patterns. Push protection blocks commits containing secrets before they land.
Code scanning (CodeQL)Threat: code-level vulnerabilities (SQL injection, XSS, path traversal, etc.). Static analysis that runs on every PR. Covered in detail in Phase 8.
Dependency reviewThreat: introducing a new vulnerable dependency in a PR. Shows a diff of dependency changes and blocks merge if any new dependency has a known CVE above your threshold.
Security advisoriesThreat: vulnerabilities in your own code that need coordinated disclosure. Private space to draft, collaborate on, and publish security advisories; can request a CVE ID from GitHub.
Private vulnerability reportingThreat: security researchers reporting bugs publicly instead of privately. Gives researchers a private channel to submit reports directly into a draft advisory without your email address.
AVAILABILITY
Most features are free for public repos. For private repos: Dependabot alerts and secret scanning are free on all plans. Secret scanning push protection, code scanning, and private vulnerability reporting require GitHub Advanced Security (GHAS) — included in GitHub Enterprise and available as an add-on for Teams.
7.2
Dependabot: Alerts vs Security Updates vs Version Updates
📚 Free Weekly Tutorials
Java, Spring Boot, AWS, DevOps & AI — straight to your inbox.
Dependabot Alerts
Dependabot Security Updates
Dependabot Version Updates
What triggers it
A CVE is published that matches your dependency graph
Same — plus GitHub can find a non-vulnerable version to upgrade to
A newer version of a dependency is available (regardless of CVEs)
What it does
Creates a security alert in the Security tab; optionally emails/Slacks
Opens a PR bumping the vulnerable package to the minimum safe version
Opens a PR bumping the package to the latest (or configured) version on a schedule
On for all dependency ecosystems; group patch updates; require review for majors
SECURITY UPDATES ≠ VERSION UPDATES
A Dependabot security update PR only bumps to the minimum version that fixes the CVE — not the latest version. A version update PR bumps to the latest. Both types can coexist; they serve different purposes. Teams that only rely on security updates can still accumulate months of version lag, increasing future upgrade friction.
A well-configured dependabot.yml keeps your dependencies fresh without drowning the team in PR noise. The key levers are scheduling, grouping, and ignore rules.
# .github/dependabot.ymlversion:2updates:# ── npm / Node.js ──────────────────────────────────────────────
- package-ecosystem:npmdirectory:/# where package.json livesschedule:interval:weeklyday:mondaytime:'09:00'timezone:Asia/Kolkataopen-pull-requests-limit:10reviewers:
- acme/platform-leadslabels:
- dependencies
- area/frontendcommit-message:prefix:chore# conventional commit prefixinclude:scope# Group all patch and minor updates into a single weekly PRgroups:non-major:update-types:
- minor
- patchmajor:update-types:
- major# Never auto-update these — they require manual testingignore:
- dependency-name:webpackupdate-types: [version-update:semver-major]
- dependency-name:typescriptversions: ['>=6.0.0'] # hold below TS 6.x until we're ready# ── Maven / Java ────────────────────────────────────────────────
- package-ecosystem:mavendirectory:/schedule:interval:weeklygroups:spring-boot:patterns: ['org.springframework.boot:*']
other-deps:patterns: ['*']
exclude-patterns: ['org.springframework.boot:*']
# ── GitHub Actions ──────────────────────────────────────────────
- package-ecosystem:github-actionsdirectory:/schedule:interval:weeklygroups:actions:patterns: ['*']
# ── Docker base images ──────────────────────────────────────────
- package-ecosystem:dockerdirectory:/schedule:interval:monthly# base images change less often
Without groups, Dependabot opens one PR per package. A large project can generate 30+ PRs per week — impossible to review meaningfully. Group patch + minor updates into a single "maintenance" PR. Keep major updates separate so they get deliberate attention. Pin framework families (Spring Boot, React, Angular) into their own groups since their packages must be updated together.
Secret scanning watches for credentials in your code. It operates in two modes: retroactive scanning (after a secret is committed) and push protection (blocking the commit before it lands).
Default patterns
GitHub maintains a list of 200+ patterns for credentials from major providers — AWS access keys, GitHub tokens, Stripe keys, Slack webhooks, GCP service accounts, Twilio keys, and dozens more. These are detected automatically without any configuration.
When a match is found on a private repo, GitHub notifies the repo admins and the commit author. For public repos, GitHub also notifies the affected service provider (e.g., AWS, Stripe) who may revoke the credential automatically.
Push protection
Push protection intercepts a push before it reaches the remote. When a secret pattern is detected, the push is rejected with a message identifying the file and pattern type:
$ git push origin mainremote: error: GH013: Repository rule violations found for refs/heads/main.remote:remote: - Push cannot contain secretsremote: —— AWS Access Key ———————————————————————————remote: locations:remote: - commit: a3f8d12remote: path: src/config.js:14remote:remote: To push, remove the secret from your commit historyremote: and try again. Alternatively, to skip this checkremote: use the GitHub web UI to allow this secret.
Removing a committed secret
# Option 1: interactive rebase to edit the offending commit$ git rebase -i HEAD~3
# Mark the offending commit as 'edit', then:$ git restore --staged src/config.js
# Remove the secret from the file, then:$ git add src/config.js
$ git commit --amend
$ git rebase --continue
# Option 2: git-filter-repo (faster for deep history)$ pip install git-filter-repo
$ git filter-repo --path src/config.js --invert-paths
# Then add the file back without the secret and re-commit# ALWAYS: revoke the secret immediately — before/during/after removal# A secret that touched GitHub's servers should be treated as compromised
REVOKE FIRST
Removing the secret from Git history does not make it safe. The secret was exposed during the push — bots scan GitHub in real-time and can capture secrets within seconds of exposure. Revoke the credential immediately, then clean the history. Treat the secret as compromised regardless of how quickly you removed it.
Bypass policies
Sometimes push protection generates false positives (a test fixture that looks like a real token). The bypass options are:
It's used in tests — the value is a test or placeholder, not a real credential
It's a false positive — the pattern matched but it's not actually a secret
I'll fix it later — acknowledge and push (creates an audit event; admin can see this)
All bypasses are logged in the audit log. Org admins can configure which bypass reasons are allowed and which require explicit org-level approval.
Custom secret scanning patterns
For internal credentials (internal API keys, custom token formats), add custom patterns:
# Settings → Security → Secret scanning → Custom patterns → New pattern
Pattern name: Acme Internal API Key
Pattern: acme_[a-z0-9]{32}
Test string: acme_k7f2m9x1q3w8e5r4t6y0u2i1o9p3a5s7
# Custom patterns support PCRE regex syntax# Push protection can be enabled per custom pattern
A SECURITY.md file tells security researchers how to report vulnerabilities. GitHub surfaces it in the Security tab and adds a "Report a vulnerability" button when private vulnerability reporting is enabled.
# SECURITY.md — production-ready template
## Security Policy
### Supported Versions
| Version | Supported |
|---------|--------------------|
| 3.x | ✅ Actively supported |
| 2.x | ✅ Security fixes only |
| < 2.x | ❌ End of life |
### Reporting a Vulnerability
**Please do not file a public GitHub issue for security vulnerabilities.**
#### Option 1 — GitHub Private Reporting (preferred)
Use the "Report a vulnerability" button in the Security tab.
We'll respond within 48 hours.
#### Option 2 — Email
security@acme.com (PGP key at https://acme.com/pgp.asc)
### Our Process
1. Acknowledge receipt within 48 hours
2. Confirm the vulnerability and assess severity within 5 business days
3. Develop and test a patch
4. Coordinate disclosure timing with the reporter
5. Release the patch and publish a security advisory
6. Credit the reporter (unless they prefer anonymity)
We follow a 90-day coordinated disclosure policy.
A "Report a vulnerability" button appears on the Security tab
Reports land in a private draft security advisory, visible only to repo admins and collaborators you invite
GitHub automatically suggests CVSS scores and CWE categories
The reporter can collaborate on the draft advisory before it's published
WHY THIS MATTERS
Without private reporting, security researchers who discover a vulnerability in your project have two bad options: email an unknown address (often ignored) or open a public issue (exposes the vulnerability to everyone). Private reporting gives them a proper channel, which means more responsible disclosures and fewer public zero-days in your code.
7.6
Repository Security Settings Checklist
A hardened private repo should have all of these enabled. Walk through Settings → Security for each repo or automate via the REST API.
Setting
Where
Recommended
Notes
Dependabot alerts
Security → Dependabot
✅ On
Free on all plans; no reason to leave off
Dependabot security updates
Security → Dependabot
✅ On
Automatically opens fix PRs for known CVEs
Secret scanning
Security → Secret scanning
✅ On
Free on all plans for private repos
Secret scanning push protection
Security → Secret scanning
✅ On (GHAS)
Blocks secrets before they land — much better than post-commit alerts
Private vulnerability reporting
Security → Private vulnerability reporting
✅ On
Free; gives researchers a responsible disclosure channel
Dependency graph
Security → Dependency graph
✅ On
Required for Dependabot alerts to work; enables dependency review in PRs
Private fork policy
Settings → General
Consider
Allow forking privately within your org for internal contributors — disable public forking if the code is sensitive
Auditing security settings across all repos in an org
Dependency Review: Blocking PRs on New Vulnerable Dependencies
The dependency review action compares the dependency manifest changes in a PR against the GitHub Advisory Database. It blocks the PR if any newly added dependency has a known CVE above your severity threshold.
# .github/workflows/dependency-review.ymlon:pull_request:branches: [main, 'release/**']
permissions:contents:readjobs:dependency-review:runs-on: ubuntu-latest
steps:
- uses:actions/checkout@v4
- uses:actions/dependency-review-action@v4with:fail-on-severity:high# critical | high | moderate | lowallow-licenses:MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISCdeny-licenses:GPL-2.0, GPL-3.0, AGPL-3.0comment-summary-in-pr:always# post a summary comment on the PRwarn-only:false# set true to surface warnings without blocking
When the action finds a problem it posts a comment on the PR showing:
The vulnerable package name and version being added
The CVE ID, CVSS score, and severity
The vulnerable version range and the minimum safe version
A direct link to the GitHub Advisory
License compliance gate
The allow-licenses / deny-licenses inputs add a licence compatibility check at the PR level — catching GPL contamination or AGPL obligations before they reach your codebase. This is particularly valuable for commercial software that can't adopt copyleft dependencies.
COMPLEMENTARY TO DEPENDABOT
Dependabot alerts tell you about vulnerabilities in existing dependencies after they're committed. Dependency review catches vulnerabilities in new dependencies being introduced via a PR — before they merge. Use both together.
When a vulnerability is found in your code (by your team or a researcher), GitHub Security Advisories give you a private workspace to draft the advisory, coordinate with the reporter, develop a patch in a private fork, and publish when ready.
Advisory lifecycle
Create a draft — Security tab → Advisories → New draft security advisory
Fill in details — affected package, vulnerable version range, severity (CVSS), CWE category, description
Invite collaborators — add the reporter and your security team; all communication is private
Request a CVE — GitHub is a CVE Numbering Authority (CNA); request a CVE ID directly from the advisory
Create a private fork — GitHub creates a temporary private fork where you can develop and review the fix without exposing it
Publish — when the fix is released, publish the advisory. It enters the GitHub Advisory Database and Dependabot begins alerting anyone who uses your package.
CVSS scoring basics
CVSS (Common Vulnerability Scoring System) v3.1 produces a score from 0–10 based on base metrics:
Score range
Severity
Typical response SLA
9.0–10.0
Critical
Patch within 24–48 hours; emergency release if needed
7.0–8.9
High
Patch within 7 days; include in next planned release
4.0–6.9
Medium
Patch within 30 days; schedule in next sprint
0.1–3.9
Low
Patch within 90 days; best-effort
GitHub's advisory UI has a CVSS calculator — fill in the attack vector (network/local), privileges required, user interaction, and impact (confidentiality/integrity/availability) and it produces the score. Don't agonise over precision; a score accurate to ±1 point is sufficient for triage.
Minimising Blast Radius with Environment-Scoped Secrets
The goal of blast radius minimisation is ensuring that if any single credential is compromised — through a leaked secret, a compromised runner, or a malicious dependency — the attacker can only reach a bounded subset of your systems.
The problem with repo-level secrets
Bad: one DEPLOY_KEY secret at repo level→ Any workflow in the repo has access to DEPLOY_KEY→ A compromised third-party action in your CI workflow accesses DEPLOY_KEY→ Attacker can deploy to production
Better: environment-scoped secrets + branch protection→ DEPLOY_KEY_STAGING in "staging" environment→ DEPLOY_KEY_PROD in "production" environment (requires manual approval)→ A compromised CI action can only reach STAGING credentials→ PRODUCTION deployment is gated by human approval in the environment
Credential scoping strategy
Credential type
Scope
Rationale
Docker registry read token (to pull base images)
Org-level
All repos need it; read-only, low blast radius
npm publish token
Repo-level
Scoped to one package; only the publish job needs it
Staging deploy key
Environment: staging
Only the deploy job targeting staging gets access
Production deploy key
Environment: production (with required reviewers)
Human approval gate + scoped credential = two-factor deploy
Database admin password
Never in GitHub secrets
Use OIDC + cloud IAM or Vault dynamic secrets instead
OIDC as the ultimate blast radius minimiser
The best approach is to eliminate long-lived credentials from GitHub entirely using OIDC (Phase 6.9). When there are no stored secrets, there are no stored secrets to steal. The OIDC token is short-lived, scoped to the run, and can only be exchanged for credentials by a job that matches your IAM trust policy claims (specific repo + specific branch).
SECURITY POSTURE CHECKLIST
For each repo, ask:
1. Do we use OIDC for cloud auth where possible?
2. Are secrets scoped to environments rather than the repo?
3. Does the production environment require a human approval?
4. Does the CI workflow run with minimum necessary permissions:?
5. Are all third-party actions pinned to a SHA?
If the answer to any of these is no, you have identified a concrete security improvement.
Up Next — Phase 8: Supply Chain Security
CodeQL and SAST integration, SARIF uploads, artifact attestations, SBOM generation, Sigstore/cosign container signing, SHA-pinned actions with Dependabot, and OpenSSF Scorecard.