Multi-tenant KEV tracking without buying another platform
I was going through the CISA KEV update on the morning of September 9th when the Cisco Secure Firewall Management Center entry landed. CVE-2026-20079, an authentication bypass, CVSS 10, unauthenticated attacker gets root through the web interface, and CISA gave federal agencies until September 12th to deal with it. Three days. If you run an MSP, the first question out of your mouth that morning was “which of my clients have FMC?”, and if you are like most of the shops I talk to, the answer was “I would have to go look,” because none of the tools you are paying for can tell you.
That question is the whole problem with KEV tooling for MSPs, so I want to walk through a pattern that answers it with free or nearly free pieces you probably already have.
The one-org assumption
Almost every KEV tracker, scanner plugin and dashboard I have looked at assumes the same shape: one organization, one asset inventory, one owner. That works fine if you are an internal security team. If you are an MSP running 20 to 200 tenants it falls apart, because you actually need two views at the same time and the tools only give you one.
You need a per-client view, so that when you are on a call with a client you can say “here is what is open for you and here is the due date.” However you also need a book-of-business view, so that when a CVE like the FMC bypass drops you can answer “which of my clients are exposed to this right now” in a minute instead of an afternoon of logging into 40 portals.
The vendors that do multi-tenant properly charge for it per tenant, and for a lot of shops that math does not work. So here is the other way.
The three pieces
The pattern is small. There are three primitives and one script that joins them.
The KEV feed — CISA publishes the Known Exploited Vulnerabilities catalog as JSON and CSV, free, no login, updated whenever they add entries. Every row has the fields you care about: cveID, vendorProject, product, dateAdded, dueDate, requiredAction and a flag for known ransomware use. That is your source of truth for “what matters right now.” You do not need to enrich it, you just need to pull it daily.
One asset CSV per tenant — this is the part people overthink. You do not need a CMDB. You need a folder with one CSV per client, and each CSV needs about six columns: hostname, vendor, product, version, internet_facing, owner. Most RMMs (NinjaOne, Datto, ConnectWise) will export this, and so will Defender, Tenable and Qualys if you already scan. The export does not have to be perfect, it has to exist and it has to get refreshed weekly. I keep mine in a private GitHub repo under tenants/, one file per client, because that gives me history for free when someone asks “did we know about that box in August?”
A roll-up board — GitHub Projects or Notion, whichever your team already lives in. One item per tenant-plus-CVE pair, with fields for Tenant, CVE, Due Date, Status and Owner. Group the board by CVE and you have the book-of-business view. Filter it by Tenant and you have the per-client view. Same data, two views, and both are free on the plans most MSPs are already on.
The join
The script is the only thing you write, and it is short. It pulls the feed, keeps anything added in the last seven days, then loops over every tenant CSV looking for a vendor and product match. Here is the PowerShell version I run, since that is what I reach for first.
$feed = ‘https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json’$kev = (Invoke-RestMethod $feed).vulnerabilities$new = $kev | Where-Object { [datetime]$_.dateAdded -ge (Get-Date).AddDays(-7) }$hits = foreach ($csv in Get-ChildItem .\tenants\*.csv) { $assets = Import-Csv $csv foreach ($v in $new) { $assets | Where-Object { $_.vendor -eq $v.vendorProject -and $_.product -like “*$($v.product)*” } | Select-Object @{n=’tenant’; e={$csv.BaseName}}, hostname, internet_facing, @{n=’cve’; e={$v.cveID}}, @{n=’due’; e={$v.dueDate}}, @{n=’ransomware’; e={$v.knownRansomwareCampaignUse}} }}$hits | Export-Csv .\kev-hits.csv -NoTypeInformationFrom there, kev-hits.csv is what feeds the board. I use the gh CLI to open one issue per row and add it to the project, but a Notion CSV import does the same job if that is where your team is. Run it on a schedule, a Task Scheduler job or a GitHub Action, and you are done. Python does this in about the same number of lines if PowerShell is not your thing.
The FMC bypass, walked through
Here is how that plays out on September 9th against a tenant folder of, say, 38 clients.
The KEV row comes in with vendorProject “Cisco” and product “Secure Firewall Management Center,” dateAdded 2026-09-09, dueDate 2026-09-12. The script runs, matches the six tenants that have an FMC in their CSV, nine hosts total, four of them flagged internet_facing. Six issues open on the board, grouped under CVE-2026-20079, each with the due date and the client’s assigned tech. Elapsed time from feed pull to a board you can screenshot for your ops lead is under two minutes, and the four internet-facing boxes go to the top of the day.
That is the book-of-business view doing exactly what you need it to do. Later in the week, when one of those six clients asks “what is open for us,” you filter by Tenant and read it off the screen.
Where it breaks, and why that is fine
I want to be honest about the edges, because this is a triage pattern, and triage is not the same thing as remediation tracking.
Vendor and product matching is fuzzy — CISA writes “Secure Firewall Management Center” and your RMM might export “Cisco FMC” or “Firepower Management Center.” You will need a small alias file that maps the KEV naming to whatever your exports use, and you will add to it every few weeks. Start with your top 20 vendors and let it grow.
It does not know versions — the join matches on product, so it will flag an FMC that was already patched. That is a false positive for closure but it is the correct behavior for triage, because you want a human to look at every one of those boxes and confirm. Version-aware matching is a scanner’s job, and you probably already have one.
Asset CSVs go stale — if the export does not get refreshed, the whole thing quietly lies to you. Put the refresh on the same schedule as the script and treat a tenant file older than 14 days as a finding on its own.
The board is not evidence — a GitHub Project shows you status. It does not show an auditor when the patch went in, who verified it, or what the exception was for the box you could not touch. For a lot of small clients that is fine. For the ones with cyber insurance questionnaires or a compliance framework, it is not.
Where this connects
Two things I would put next to this pattern.
The first is the KEV Triage Checklist, which is the free one-page process I use for the decision on each hit: is it reachable, is it patchable in the window, and if not, what is the compensating control and who signed off. The script tells you which tenants are exposed, the checklist is how you work each row in 15 minutes without missing the same step twice. It is free on Gumroad at opstacks.gumroad.com/l/kev-triage.
The second is RemedyOps, which is where anything you actually need to track long term should go. RemedyOps is the GitHub-native remediation tracker I built for exactly the gap in the last section: it takes the scanner output or a hits file like this one and turns it into an SLA-driven workflow with evidence attached to each ticket, so when the client or the auditor asks for proof you have it. The triage board in this post is the cheap front door, RemedyOps is the system of record for the clients that need one. The MSP tier is built for the multi-tenant case, and it is at opstacks.gumroad.com/l/pzrrr.
If you are running some version of this already I would like to hear how you handled the naming problem, since that is the part that ate most of my time. Email me at opstacks@outlook.com, or subscribe to the OpStacks Weekly Digest and reply to any issue, and let me know what you think.
Curtis
Sources for the CVE-2026-20079 details: BleepingComputer · The Hacker News · CISA KEV catalog