Two problems share a cluster here because they arrive through the same pull request, and are otherwise almost nothing alike.
Code you wrote can contain vulnerabilities you introduced, which you can fix by changing the code. Code you depend on can contain vulnerabilities somebody else introduced, in a package you may not have chosen, at a depth in the tree you have never looked at — and your remediation options are upgrade, replace, or accept.
Conflating them produces the two classic failures: treating a dependency advisory as an emergency when the vulnerable function is never called, and treating a static-analysis finding as noise when it is a real path from user input to a database.
Start with GitHub Code ScanningThe model
Section titled “The model”Source code splits into two branches. On the left, static analysis via code scanning and CodeQL. On the right, dependencies, analysed by the dependency graph, Dependabot and dependency review. Both converge on the pull request.
The left branch asks “does this code do something dangerous with data it does not control?” The right branch asks “what is in here that I did not write, and is any of it known to be bad?”
Neither answers the other’s question, and neither replaces review.
Detection and remediation are separate systems
Section titled “Detection and remediation are separate systems”The most useful framing for this cluster is that GitHub gives you four tools that are commonly described as one product, and they do genuinely different jobs.
| Tool | Question it answers | Trigger |
|---|---|---|
| Code scanning | Does the source contain a pattern that represents a vulnerability? | Push, pull request, schedule |
| Dependency graph | What does this repository actually depend on, including transitively? | Manifest and lock file changes |
| Dependabot | Is anything I already depend on known to be vulnerable, or out of date? | Advisory publication, schedule |
| Dependency review | Does this pull request make dependency risk worse? | Pull request |
The fourth is the one teams most often skip, and it is the only one positioned to prevent rather than report. Dependabot tells you about a problem you already have. Dependency review tells you about a problem you are about to acquire, at the moment somebody can still decide not to.
The threat model
Section titled “The threat model”Threat. A defect reaches production — either written into first-party code, or pulled in with a dependency — and is reachable by an attacker.
Attack surface. Every code path that handles input the attacker influences: request parameters, uploaded files, message queues, environment configuration. Plus the entire transitive dependency tree, plus the package resolution process itself, which decides which artifact a name resolves to.
Impact. Ranges from nothing (the vulnerable code path is unreachable in your usage) to complete compromise. That range is why blind patching by severity score is a poor strategy: severity describes the vulnerability, not your exposure to it.
Control. Static analysis on every pull request; a complete dependency inventory; automated updates with enough CI to make them safe to merge; and a review gate on dependency changes.
Verification. Introduce a known-vulnerable dependency in a scratch repository and confirm the pull request is annotated. Confirm a deliberately vulnerable code pattern is caught — and note which of your real patterns are not.
Alert fatigue is a security failure
Section titled “Alert fatigue is a security failure”Worth stating plainly, because it is usually treated as an operational annoyance rather than a control failure.
A team with 400 open Dependabot pull requests has the same effective security posture as a team with Dependabot switched off, minus the time spent ignoring the tab. Detection that nobody acts on is not detection; it is a record that would have been useful.
Every tool in this cluster has noise controls, and using them is not a compromise:
- Grouped updates turn twelve pull requests into one.
- Cooldown periods let a fresh release settle before you take it.
- Auto-triage rules dismiss classes of alert that do not apply, with a stated reason.
- Severity thresholds on the dependency review action decide what blocks a merge.
- Query suites control how aggressive code scanning is.
Tuning these is how the queue stays short enough that a real finding is visible in it.
The lessons
Section titled “The lessons”- Lesson 1: 01. GitHub Code ScanningCode scanning as a platform — default and advanced setup, third-party SARIF tools, alert severity and lifecycle, pull request behaviour, merge gating through rulesets, and organisation rollout.
- Lesson 2: 02. CodeQLCodeQL explained — databases, queries and query suites, supported languages and build modes, default and advanced setup, custom query packs, triage and the analysis's real limits.
- Lesson 3: 03. DependabotThe three Dependabot systems explained — alerts, security updates and version updates — with dependabot.yml configuration, grouping, cooldowns, auto-triage rules and noise control that works.
- Lesson 4: 04. Dependency ReviewReviewing dependency changes at the pull request — what dependency review shows, the action's severity, scope, licence and package controls, OpenSSF Scorecard signals.
- Lesson 5: 05. Dependency GraphThe inventory everything else reads from — how the dependency graph is built from manifests and lock files, direct versus transitive dependencies, the dependency submission API.
- Lesson 6: 06. Vulnerability AlertsTurning advisories into decisions — severity versus exposure, reachability, the advisory database, dismissal reasons, auto-triage rules.
- Lesson 7: 07. Copilot AutofixAI-suggested fixes for code scanning alerts — what Autofix covers, how GitHub validates suggestions before showing them, its documented failure modes.
- Lesson 8: 08. Security CampaignsManaging security debt at scale — what a campaign is, alert selection and templates, deadlines and ownership, developer notification, Autofix integration, tracking, and the limits worth knowing.
Lessons 1 and 2 cover static analysis: the platform feature, then the engine underneath it. Lessons 3 to 6 cover the dependency side, deliberately starting with the graph — you cannot manage what you have not inventoried. Lesson 7 covers AI-suggested fixes with the scepticism they require. Lesson 8 covers remediating at organisational scale, which is a different problem from remediating one alert.
Remediation differs, and that is the point
Section titled “Remediation differs, and that is the point”The reason to keep first-party and third-party findings mentally separate is that the fix looks nothing alike.
A first-party finding is a defect in code you control. You can read the surrounding function, decide whether the reported path is genuinely reachable, and change it. The main risks are misjudging reachability and fixing the symptom — sanitising one call site while leaving the pattern in place elsewhere.
A third-party finding is a defect in code you do not control, and your options are constrained:
- Upgrade to a fixed version, which is usually right and occasionally impossible because the fix landed in a major release with breaking changes.
- Pin a transitive dependency through your package manager’s override mechanism, which fixes the resolved version without waiting for your direct dependency to update. This works, and it silently puts you on a combination the maintainer never tested.
- Replace the dependency, which is a project, not a patch.
- Accept the risk with a documented reason — legitimate when the vulnerable code path is genuinely unreachable in your usage, and dangerous as a habit because “unreachable” changes when your code does.
Notice that three of those four are decisions about your system that no scanner can make for you. The tooling’s job is to put a correct, complete question in front of the person who can answer it.
How the tools fit together
Section titled “How the tools fit together”They are frequently described as alternatives. They are layers, and each depends on the one before.
- The dependency graph is the substrate. It parses manifests and lock files to determine what you actually depend on, direct and transitive. Nothing else in the dependency chain works without it.
- Dependabot alerts join that inventory against the GitHub Advisory Database. New advisory, or new dependency — either can produce an alert.
- Dependabot updates act on those alerts, and separately keep versions current so that when an urgent upgrade is needed you are not also absorbing two years of drift.
- Dependency review watches the change, in the pull request, before any of the above becomes your problem.
On the static analysis side the layering is shallower but the same shape: code scanning is the platform — alerts, pull request annotations, SARIF ingestion, merge gating — and CodeQL is the analysis engine GitHub ships for it. Third-party analysers that emit SARIF plug into the same platform, which means the triage workflow stays identical whichever engine produced the finding.
Prerequisites
Section titled “Prerequisites”Common mistakes
Section titled “Common mistakes”Enabling everything on day one. Turning on code scanning across an organisation produces a backlog measured in thousands, and a backlog nobody can triage teaches everyone to ignore the interface. Start with the default query suite on active repositories.
Treating the dependency graph as complete. It reads manifests and lock files. Vendored code, system packages installed in a Dockerfile and dynamically fetched dependencies are invisible to it unless submitted explicitly.
Merging Dependabot pull requests without CI. An automated dependency bump with no test coverage is an automated production change with no test coverage.
Dismissing alerts without a reason. The dismissal reason is the only record of the judgement. Without it, the next person re-does the analysis or, more often, re-opens the argument.
After this cluster
Section titled “After this cluster”Code and dependency security is about what is in the software. The final cluster is about the software’s journey: whether the artifact you deploy was built from the source you reviewed, by the system you expect, and whether anyone downstream can check that independently.
Next cluster — Software Supply Chain Security