Nullify

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

How to Run a Vulnerability Remediation Campaign in 9 Steps

To run a vulnerability remediation campaign, pick one class of finding (a vulnerable dependency, a leaked secret pattern, an unsafe helper), define what "done" looks like, and scope every affected repository. Then work it to closure with named owners, a paced flow of fixes and a progress count.

A campaign replaces dozens of disconnected tickets with one objective. The point is not to close more tickets. It is to make one class of risk disappear and stay gone.

This guide covers what a remediation campaign is, when to run one, nine steps from scope to closure, a plan template and a checklist.

What is a vulnerability remediation campaign?

A vulnerability remediation campaign (sometimes called a security campaign) is a time-bound effort to fix one class of vulnerability everywhere it appears. It has a single objective, a defined scope, named owners, a pace, a deadline and a measurable finish line.

A typical objective reads like "upgrade every service off the vulnerable version of this library."

Here's how a campaign differs from the normal remediation queue:

Ticket queueRemediation campaign
Unit of workOne findingOne class of finding
GoalClose ticketsReach a defined end state
FixWritten separately each timeOne fix pattern, applied everywhere
ProgressTicket countResolved vs. remaining, by team
Ends whenNeverThe end state is reached and verified

When to run a remediation campaign

Campaigns are worth the setup when the same fix applies in many places. Common triggers:

  • A vulnerable dependency across many services. The same library version sits in dozens of repositories.
  • A newly exploited vulnerability. A CVE you depend on is added to the CISA Known Exploited Vulnerabilities Catalog, and you need to know you're clear everywhere.
  • A secret pattern. A class of credential has been committed in several repositories and needs removing and rotating.
  • A repeated insecure pattern. The same unsafe deserialization helper or missing authorization check was copied between teams.
  • A framework or runtime end of life. A major version stops receiving security fixes.
  • An audit or customer commitment. You've promised a class of risk will be gone by a date.

If a fix applies in one or two places, a normal ticket is faster. Campaigns pay off when you need to fix vulnerabilities at scale.

Which campaign to run first

When several candidates qualify, start with the class that is actively exploited, reachable in deployed code and present in internet-facing services. Instance count matters less than exposure. A small campaign on a known-exploited CVE beats a large one on a theoretical finding.

How to run a vulnerability remediation campaign

1. Set one objective with a measurable end state

Write the objective as a result, not an activity. "No production service runs library below version X" is an end state, and "work on dependency upgrades" isn't.

Run several narrow campaigns over time rather than one campaign for everything. A narrow campaign is easier to staff, track and finish.

2. Scope it with filters and freeze a baseline

Define the scope as a filter you can re-run: CVE or CWE, finding type, repositories, teams and severity. Then record the starting count.

The baseline is what makes progress visible. The re-runnable filter catches new instances that appear mid-campaign.

3. Rule out what doesn't need fixing first

Before anyone writes a fix, remove noise from the scope. Check whether each instance is reachable, deployed and exposed, and whether it lives in test or dead code.

Decide up front how out-of-scope items will be recorded (accepted risk, not reachable, mitigated) and who signs off. Mitigations are not remediations, so track them separately and give them a review date.

4. Find the fix pattern

A campaign moves fast when the fix is the same everywhere: one version bump, one shared helper replaced, one config change.

Prove the fix on two or three representative repositories first. Include at least one hard case, such as an old service, a pinned transitive dependency or a monorepo. Write down the pattern and the known exceptions before you roll it out.

5. Assign owners, a campaign manager and a kickoff message

Each affected repository or service needs an owner who will review and merge the fix. Take owners from CODEOWNERS, commit history and service metadata rather than guessing.

Name one campaign manager who answers questions, handles exceptions and reports progress. Don't move work across team boundaries without the receiving team agreeing.

Before the first fix lands, tell owners what is coming: the objective, why it matters now, the deadline, and who to ask. Developers review a PR they expected far faster than one that arrives unannounced.

6. Pace the work so developers can absorb it

The fastest way to fail a campaign is to open 200 pull requests in one afternoon. Developers learn to ignore a wall of PRs.

Instead, cap the number of open fix PRs per repository and per campaign, and take each owner's current workload into account when assigning. A steady flow that gets merged beats a flood that gets closed.

7. Deliver fixes as pull requests that already pass

Each fix should arrive as a pull request with a minimal change, a short explanation of the vulnerability and what changed, and a passing build and test run. If the build fails, fix it before asking for review.

A human should approve every merge.

8. Track progress and escalate stalls

Report resolved versus remaining for the whole campaign and for each team, not just a ticket count.

Set an SLA for how long a campaign PR can sit unreviewed. Escalate stalls to the owner and their lead in the channel they actually read, with the risk and the deadline stated.

9. Verify, close and prevent the next one

A campaign isn't done when the PRs merge. Re-scan to confirm every in-scope instance is gone, and confirm the fix is deployed, not just merged.

Then stop it coming back. Add a pull request check or rule that blocks the vulnerable version or pattern, and record what you learned for the next campaign.

Remediation campaign plan template

Fill this in before step 4. If you can't fill a row, the campaign isn't ready to start. The example is illustrative.

FieldExample
ObjectiveNo production service depends on example-lib below 4.2.1 (CVE affecting request parsing).
Why nowThe CVE was added to the CISA KEV catalog.
Scope filterCVE = the listed CVE; all repositories; dependency findings only.
Baseline38 instances in 31 repositories across 6 teams.
Out of scopeInstances in archived repositories or unreachable test tooling, recorded with reason and owner sign-off.
Fix patternUpgrade to 4.2.1; for services pinned by framework X, upgrade the framework to its next minor version.
OwnersFrom CODEOWNERS and recent commit history; campaign manager named.
KickoffMessage to all owners with objective, deadline and contact.
PaceAt most a few open campaign PRs per repository at a time.
Review SLACampaign PRs reviewed within an agreed number of business days, then escalated in Slack.
DeadlineSet from the risk tier and the number of instances in scope.
Done whenRe-scan shows zero in-scope instances and fixes are deployed.
PreventionPull request check blocks versions below 4.2.1.

Common remediation campaign mistakes

  • Scoping too broadly. "Fix all criticals" is a backlog, not a campaign. Pick one class.
  • Skipping the noise check. Fixing unreachable instances first burns goodwill you'll need for the real ones.
  • Flooding developers. Unpaced bulk PRs get ignored or closed.
  • Closing by suppression. Accepting risk to hit the deadline makes the number move without reducing exposure. Report it separately.
  • No verification. Merged isn't deployed, and deployed isn't proven until a re-scan agrees.
  • No prevention. Without a pull request check, nothing stops the same pattern from being copied back in.

Remediation campaign checklist

  • The objective is a measurable end state.
  • Scope is a re-runnable filter with a recorded baseline.
  • Unreachable, undeployed and test-only instances are handled before fixes start, with a recorded reason.
  • Mitigations are tracked separately from remediations.
  • The fix pattern is proven on representative repositories, including a hard case.
  • Every repository has a named owner, the campaign has a manager, and owners got a kickoff message.
  • Open fix PRs are capped per repository and per campaign.
  • Every fix PR passes the build and tests before review, and a human approves each merge.
  • Progress is reported as resolved vs. remaining, per team.
  • Stalled PRs are escalated against an SLA.
  • Closure is verified by a re-scan and deployment check.
  • A pull request check prevents the class from returning.

How Nullify runs remediation campaigns

Campaigns are part of Nullify's security program management. Security leaders set the objective, the scope and how much Nullify automates.

Campaigns are built from real findings and can target code, dependency, secret and pentest findings, filtered by type, CWE, CVE, repository, team, individual or severity. Owners come from CODEOWNERS, commit history and service metadata, and assignment accounts for each person's open PRs and tickets.

Where a code change resolves the issue, Nullify opens a minimal, build-validated fix and manages it through review. It keeps at most 3 open fix PRs per repository and 5 per remediation plan.

Stalled PRs and tickets are escalated in Slack with the risk and SLA stated, and campaign reporting shows resolved versus remaining for each team. Developers approve every merge. Nullify never auto-merges.

Frequently asked questions

What is the difference between a remediation campaign and a vulnerability remediation plan?

A vulnerability remediation plan usually covers everything a team intends to fix over a period. A campaign is one focused part of that plan: a single class of vulnerability, a defined scope, owners and a finish line. Many teams run their remediation plan as a series of campaigns.

How long should a vulnerability remediation campaign take?

It depends on the risk and the number of instances. An actively exploited vulnerability in internet-facing services needs days. A dependency upgrade across dozens of internal services can run for several weeks. Set the deadline from the risk tier and the scope, then check it stays achievable as the campaign progresses.

How many pull requests should a campaign open at once?

Fewer than you think. Cap open fix PRs per repository and across the campaign, and consider each owner's current workload. A steady flow that gets reviewed and merged finishes sooner than a large batch that developers ignore.

How do you measure campaign success?

Track resolved versus remaining against the baseline, by team, plus time to merge for campaign PRs. The campaign succeeds when a re-scan confirms zero in-scope instances, the fixes are deployed, and a pull request check stops the class from coming back.