2026-05-21 · 4 min read

Two Systems, One Endpoint, and No Agreement

The EDR platform and the RMM platform each knew things about the same machine that the other did not, and neither could answer the only question that mattered.

security · cve · integration

The question came down from leadership in the form it always takes: are we patched. Four words, asked in good faith, with an expected answer length of one sentence.

I had two consoles open, and they did not agree.

Two true accounts of the same estate

The EDR platform knew about vulnerabilities. It could tell me which CVEs it had observed on which agents, with severities attached, and it was confident about it. The RMM platform knew about the estate — what machines exist, who owns them, what is installed on them, which ones have an agent at all. Also confident.

Neither was wrong. They were built to answer different questions and they had each answered theirs correctly. The trouble is that "are we patched" is a question about the intersection, and the intersection was not a thing either product held. A vulnerability finding with no owner and no context is not actionable, and a complete inventory with no vulnerability data is not a security posture. I had two halves and no join.

The join is the work

I assumed the integration would be mostly API plumbing and that the interesting part would come later. It was the reverse.

The two systems do not agree on what a machine is called. Hostnames drift, get renamed, get reimaged and come back looking like a new device to one system and the same device to the other. An endpoint can exist in one platform and not the other, for reasons that are usually legitimate and always need checking. Serial numbers help until you meet the hardware where they do not.

So a reconciliation layer had to exist: a deliberate, written-down set of rules for deciding when a record on one side and a record on the other are the same physical machine, plus a place for the ones that could not be matched to sit visibly instead of quietly falling out of the count. The unmatched list turned out to be the most useful output of the lot. Every entry on it is either a gap in coverage or a gap in the matching, and both are worth knowing.

Not every finding is an action

Once the join existed, the next lesson arrived quickly. A CVE with no available patch is not an action item. It is a fact about the software, and putting it in front of an engineer as work produces nothing except the erosion of their willingness to read the next list.

So findings get checked against NVD before they are presented as anything. Is there a fixed version. Does it apply to this platform and this configuration. If there is no remedy, the finding is still tracked, but it is tracked as a condition to monitor rather than as a task somebody has failed to complete. The difference between those two framings is most of whether a vulnerability programme is trusted internally.

Remediation in the same pane

The other thing I did not want was for the output to be a ticket. A ticket is a description of an act, handed to somebody else, with a queue in between. When the system already knows which machine, which package, and which fixed version, the distance between knowing and doing should be short.

So there is a Python sidecar that performs the remediation directly: WinRM to the Windows estate, SSH to everything else, driven from the same interface that surfaced the finding. Same identity mapping, same reconciliation, same place. The thing that found the problem is the thing that fixes it.

Where the fragility sits

Two vendor APIs are now load-bearing, which means two upstream release schedules I do not control can break my Tuesday. Both have rate limits, and respecting them shapes the design more than I would like — full estate reconciliation is not something you can do casually in a loop, so it runs on a schedule with incremental updates in between. The picture is eventually consistent rather than live, which is a tradeoff worth naming out loud rather than discovering.

And the reconciliation layer itself is now infrastructure. It is code I wrote that sits between two commercial products and produces the numbers people make decisions from. If its matching rules are wrong, both consoles will continue to be perfectly correct and the answer on the screen will be quietly false. That is the failure mode I watch for, and the unmatched list is how I watch for it.

The single-sentence answer to "are we patched" still does not exist. What exists now is one number, produced by rules that are written down, with the machines it could not account for listed underneath it.

All field notes