Skip to main content
GitHub DevSecOps Part 9: Vulnerability Management
  1. Blogs/

GitHub DevSecOps Part 9: Vulnerability Management

Author
Romano Roth
I believe the next competitive edge isn’t AI itself, it’s the organisation around it. As Chief AI Officer at Zühlke, I work with C-level leaders to build enterprises that sense, decide, and adapt continuously. 20+ years turning this conviction into practice.
Ask AI about this article

We have spent the previous eight sessions adding scanners to our GitHub DevSecOps pipeline — SCA, SAST, container scanning, secret detection, DAST. The scanners now produce a steady stream of findings, and the question is: where do we manage them? In Part 9, Patrick Steger and I look at GitHub’s built-in Vulnerability Management — the Security Tab — and call out what it does well and what is still missing.

Where Vulnerabilities Live on GitHub
#

Everything happens in the Security Tab. There are two distinct sections. Code Scanning holds findings from the scanners we wired into the pipeline — CodeQL plus any SARIF-producing tool. Secret Scanning is GitHub’s own integrated secret detection, with its own UI.

Why two different UIs? We do not really know. Our best guess is that Secret Scanning is treated as a platform feature with a special workflow, while Code Scanning is the generic ingestion point for everything else. In practice you switch between them often, and the inconsistency takes some getting used to.

Vulnerabilities are tracked across all branches where the pipeline ran the scanners. The branches close to production are obviously the ones to focus on, but you can filter by branch when you need to.

The Capabilities GitHub Gives You
#

For each finding you can sort and filter by tool, branch, severity, and rule (the rule filter is honestly not very useful unless you know exactly what you are looking for). From a finding you can:

  • Create an issue to hand work off to a developer. The vulnerability and the issue link both ways.
  • Dismiss with a reason: false positive, won’t fix (we accept the risk), or used in tests (it is in test code, not production). Crucially, you can — and should — add a comment explaining the decision.
  • Track history. GitHub shows when the finding was first detected, on which branch it appeared, when it was fixed, and if it reappeared.

There is no explicit “resolved” button. When the scanner stops reporting a finding on the next pipeline run, GitHub closes it automatically.

You can integrate additional scanners as long as they produce SARIF format. SARIF is at least a standard, so this is not a heavy constraint.

The Limitations to Plan Around
#

Patrick is direct about where GitHub falls short.

No time-boxed dismissal. You cannot dismiss a finding for two weeks or two months. Sometimes you want a finding to go away “for now” — there is no fix yet, or the team needs to ship something else first — but GitHub does not let you defer cleanly.

You cannot change the severity. If the tool says “high,” it stays “high.” Compensating controls in your environment may genuinely make it medium or low, but GitHub does not let you reflect that.

Manual triage is unavoidable. Every Vulnerability Management tool needs human review for false positives and duplicates. That is not a GitHub-specific issue, but plan for the effort.

No manual entries. This is the one Patrick really hates. If you commission an external penetration test and the tester finds ten new vulnerabilities, you cannot add them to the GitHub Vulnerability Management. You need a separate tool for anything found outside the platform — a serious limitation if penetration testing is part of your process.

Triage Workflow in Practice
#

In the demo we worked through the realistic flow. In Secret Scanning the findings are clear: a title, a reference to the secret, and a remediation recommendation. You know what the problem is and what to do.

In Code Scanning we filtered to CodeQL and opened a “use of broken or risky cryptography” finding — an MD5 instance we had assessed before. We use it for indexing, not for security, so we dismissed as false positive with the comment “it’s just for indexing.” That comment is the difference between a useful audit trail and a black box.

Next we opened a real cross-site scripting finding — a message returned to the caller and reflected. Real issue. We created an issue directly from the finding. GitHub jumps to the new issue with the link back to the vulnerability, and the vulnerability page shows the linked issue. Two-way linking works well.

To fix it we used the file view to navigate to the source, switched to the main branch, edited inline, and saved. The pipeline ran in Actions, CodeQL re-scanned, and the open count for the rule dropped to zero. Under the closed filter the cross-site scripting finding shows up as resolved minutes ago.

One thing to know: the issue we created is not auto-closed when the vulnerability is. The developer (or you) has to close it manually. Arguably acceptable — closing it by hand is the developer’s confirmation that the fix is deployed — but it is not automatic.

Key Takeaways
#

  1. One tab, two UIs. Secret Scanning and Code Scanning live in the same Security Tab but have different UIs. Get used to switching.

  2. Default branch is not the only branch. GitHub tracks findings across branches, which is more flexible than the default-branch-only view some other platforms give you.

  3. Dismissal reasons are first-class. False positive vs won’t fix vs used in tests, plus a comment field. Use them — they are the audit trail.

  4. No time-boxed dismissal. If you need “ignore for two months,” you have to track it outside GitHub. A label and a calendar reminder is the realistic workaround.

  5. No manual entries is the biggest gap. Findings from external penetration tests cannot be added. If pen-testing is part of your process, plan for a second tool.

  6. Issues and vulnerabilities link both ways but close independently. Create an issue from a finding, fix the code, the vulnerability auto-closes — but remember to close the issue too.