|Josh Ghent

The SOC 2 patching SLA nobody talks about — and how to actually meet it

soc2cvecompliancepatching slavulnerability management

The SOC 2 patching SLA nobody talks about — and how to actually meet it

Picture the scene. It's the third week of your SOC 2 Type II audit. The auditor opens a screen-share, pulls up a Wiz export you handed over a fortnight ago, and points at a row.

"This CVE — critical, CVSS 9.1 — was first detected on March 4th. The fix landed on May 18th. That's 75 days. What's your remediation SLA?"

You say "30 days for criticals." They nod, write something down, and ask for another twelve examples. By lunchtime you're sweating because you know the pattern is going to repeat. The Dependabot PR was opened on day 2. It just sat there. CI was red. Nobody owned it. By the time someone rebased it, the parent package had moved on and the bump was harder than it should have been.

I've been on both sides of this conversation. Last year I patched 200+ CVEs by hand across a regulated estate, and the single most common audit finding wasn't "you don't have a vulnerability management policy." Everyone has the policy. The finding was "your policy says 30 days, your evidence says 60+." That gap is what this post is about.

What SOC 2 actually says about patching

SOC 2 doesn't hand you a number. There is no clause that reads "thou shalt patch criticals in 30 days." The relevant Trust Services Criteria sit under the Common Criteria — broadly CC7.1 (the entity uses detection and monitoring procedures to identify changes to configurations that result in vulnerabilities) and CC7.2 (the entity monitors components for anomalies indicative of malicious acts, natural disasters, and errors). There's also CC6.6 / CC6.8 territory around managing vulnerabilities in the system boundary.

What auditors are actually doing is checking three things:

  1. You have a documented vulnerability management policy with defined severity tiers and remediation timelines.
  2. You can demonstrate you follow it consistently across the in-scope estate.
  3. The timelines are reasonable for the risk — typically critical/high in 30 days, medium in 60–90, low in 90+.

The 30-day figure isn't pulled from the standard. It's the de facto industry benchmark inherited from PCI-DSS 6.3.3 (which does prescribe 30 days for critical patches), NIST SP 800-40, and your auditor's other clients. Once you write it into your own policy, it becomes the bar you're held to.

That's the bit teams underestimate. Your policy is the SLA. If your policy says 30 days and your median time-to-remediate is 47, you have a SOC 2 problem regardless of what the framework technically requires.

Why teams blow through the 30-day window

I've audited internal teams on this and the failure modes are remarkably consistent. It's almost never "we didn't know about the CVE." Tenable, Wiz, Snyk, GitHub Advanced Security — the detection layer is solved. The breakdown happens between detection and merge.

1. Dependabot PR rot

Dependabot opens a PR on day 2. CI fails on day 2. Nobody looks at it. By day 20 the branch has 14 commits of drift behind main. By day 30 the auto-rebase fails. By day 45 the package itself has shipped two more versions and the PR is essentially abandoned.

This is the single biggest killer. If you want to see it in your own repos, sort open PRs by oldest and filter by author dependabot[bot]. The number that come back is usually embarrassing. I wrote a longer comparison of Dependabot, Renovate, and what fills the gap if you want the tooling angle.

2. Transitive dependencies stuck behind a parent

Your scanner flags [email protected] as vulnerable. You don't depend on ws directly — socket.io does, and it pins to that version. You can't bump ws without bumping socket.io, and bumping socket.io is a breaking change that touches your real-time layer.

So the CVE sits there for six weeks while someone gets cycles to do the parent upgrade properly. Your scanner keeps reporting it. Your auditor sees a 42-day age on a critical and asks why.

3. CI failures nobody fixes

The bump from @types/node@18 to @types/node@20 introduces a type error in two files. The fix is fifteen minutes of work. But the PR is from a bot, the failure is in TypeScript not in the bot's logic, and no human is assigned. So it sits.

Multiply that by every minor breaking change in a year and you have a queue of trivially-fixable PRs that never merge.

4. The ownership gap

This is the quiet one. The Platform team thinks the App team owns it because it's their package.json. The App team thinks Platform owns it because it's "security." Neither team has it on a board. The PR has no assignee, no reviewer, no due date. The only thing tracking it is the scanner reminding you every Monday that it's still there.

A minimum viable workflow that actually closes vulns inside SLA

I've tried elaborate versions of this with Jira automations, Slack bots, and weekly security stand-ups. The version that actually works is much smaller.

Step 1: One queue, not five

Pick one source of truth for "what's open right now." Wiz dashboard, GitHub Security tab, a Linear view — doesn't matter, but it has to be one place. Every CVE in scope shows up there with three columns: severity, age in days, owner. If you're tracking it in three tools you're tracking it in zero.

Step 2: Auto-assign on detection

The moment a CVE PR is opened or a scanner finding lands, it gets a CODEOWNER and a due date. No PR sits in "unassigned" purgatory. If your CODEOWNERS file is wrong or stale, fix that first — it's the highest-leverage hour you'll spend this quarter.

Step 3: A bot that fixes its own CI

Most Dependabot PRs that fail CI fail for boring reasons: a lockfile drift, a snapshot test, a type bump that needs a one-line change in a downstream file. A human can fix it in ten minutes. The problem is queueing those ten minutes against everything else on a sprint.

This is the gap I built RepoWarden to fill — when CI fails on a security PR, the bot reads the failure, writes the fix, pushes a commit, and re-runs CI. Same end state as a human did it, but it happens in minutes instead of weeks.

Step 4: Friday triage, 30 minutes, non-negotiable

Whatever's left after the bot's done its job goes into a 30-minute Friday slot. One engineer, one PM, one screen. Merge what's mergeable. Bump the parent for stuck transitives. Escalate the rest with a written reason. Done.

Step 5: Track median, not max

Don't report "longest open CVE." Report median time-to-remediate by severity. Median is the metric your auditor implicitly cares about because it tells them whether the process works in the average case. A single 90-day outlier is explainable. A median of 47 is not.

The evidence trail auditors actually want

This is where most teams lose marks even when their patching is fine. The work happened, but the evidence is scattered across Slack DMs, deleted branches, and the tribal knowledge of one senior engineer who's on holiday.

Here's the evidence pack that makes audits boring:

  • The PR itself, with a description that names the CVE ID, severity, the affected package, and the fix version. "Bump lodash from 4.17.20 to 4.17.21" is not enough. "Bump lodash from 4.17.20 to 4.17.21 — addresses CVE-2021-23337 (CVSS 7.2, command injection in template)" is.
  • Commit attribution — the merge commit shows who reviewed and who merged. If a bot pushed the fix, the bot's identity should be a real GitHub App with a documented purpose, not a personal access token on a service account.
  • CI logs preserved showing tests passed before merge. GitHub keeps these for 90 days by default; if your audit window is a year, you need to extend retention or archive them.
  • Scanner before/after — a Wiz or Tenable export showing the finding closed, dated after the merge.
  • A ticket or change record if your policy requires one. It doesn't have to be Jira; a closed GitHub Issue linked to the PR works fine, as long as it's consistent.

If you want a single piece of advice from this post, it's this: write the PR description as if the auditor is the only person who'll ever read it. Because eventually one of them will. I now keep a forward-link to a per-CVE detail page for every finding I close, because pasting the same vendor advisory into twelve PR descriptions a quarter is a waste of human time.

Why this is hard to do with people alone

You can absolutely run this workflow manually. I did, for a year. The reason most teams don't sustain it isn't laziness — it's that the volume scales faster than headcount. Five PRs a week is fine. Fifty in a quarter, with half of them needing CI babysitting, is a part-time job nobody signed up for.

That's why the bot-fixes-its-own-CI step matters more than any of the others. It's the only one that makes the maths work as your repo count grows. Group updates help, scheduling helps, ownership helps — but if a human still has to chase every red build, your median will creep back over the line within two quarters.

What RepoWarden does end-to-end

I'll be direct: I built RepoWarden because I wanted a thing that did the boring 80% of this on its own and let me focus on the 20% that actually needs judgement.

It watches your repos, opens fix PRs for CVEs and stale dependencies, fixes its own CI when the build goes red, routes the PR to the right CODEOWNER, and writes the audit-ready PR description for you. Median time-to-remediate on the regulated estate I run drops from weeks to days, and the evidence trail is consistent because a machine wrote it the same way every time.

If your next SOC 2 is in the diary and you're squinting at a backlog of open CVEs wondering how this conversation is going to go — run an audit on a repo. No signup, no card. It'll tell you in about a minute where your gap actually is. From there you can decide whether to fix it with people, with us, or with a mix of both.

Either way, please write the PR descriptions properly. Future you, sat across a screen-share from an auditor in May, will thank current you.

Free instant repo audit

See how many engineering hours you'd reclaim

Paste any public GitHub repo. We scan for outdated dependencies, committed secrets, missing CI, weak coverage and more — then estimate the engineering time RepoWarden would save you.

No sign-up required to see the report · Public repos only · Read-only public API

Ready to automate your dependency updates?

RepoWarden keeps your repos secure and up to date — with supply chain protection, automated testing, and clean PRs.

Get started free