What Linux patch evidence should include before you close a vulnerability
Package version evidence is useful, but it is not always enough to close a Linux vulnerability. Here is the host-level evidence worth collecting before calling a finding remediated.
Most vulnerability closures do not get messy because nobody ran the patch command.
They fail in the gray area after that.
The package was updated. The scanner finding changed state. There is a screenshot, a command transcript, or a note in the change record. The maintenance window is over. Everyone would like to close the work and move on.
Then somebody asks the question that slows the room down:
What evidence do we actually have that this Linux host is remediated?
For a lot of teams, the answer is a mix of package versions, scanner exports, shell output, Slack messages, reboot notes, and a little bit of institutional memory. That is normal. It is also fragile.
On Linux, a package update is only one part of the evidence. A fixed package can be installed on disk while old code is still mapped into a long-running process. A fixed kernel can be present while the host is still booted into the vulnerable kernel. A scanner can be right about the CVE and still not tell the operator what action is left.
If you are the person deciding whether a vulnerability is closed, the useful question is not just:
Did the package update?
It is:
What proof do we have that the vulnerable code is no longer live, or what action is still required?
That proof does not need to be fancy. It does need to be specific.
Package version evidence is necessary, but not sufficient
The package database is a good place to start. On RHEL-family systems, rpm, dnf, vendor advisories, OVAL data, and scanner plugins can tell you a lot:
- which package is installed
- which epoch/version/release is installed
- whether the distro vendor has shipped a fixed package
- whether the installed package is older than the vendor-fixed build
- when the package was last updated
That is real evidence. Keep it.
But do not treat it as the whole host.
A package manager mostly answers a disk-state question:
What is installed now?
A vulnerability closure usually needs a remediation-state answer:
Is the vulnerable code still running?
Those are related questions, but they are not the same question.
If openssl-libs was updated while nginx kept running, the package on disk may be fixed while the worker process still maps an old libssl object. If a kernel fix was installed but the machine did not reboot, rpm and uname -r are going to tell different stories. Both stories matter.
This is why closure evidence should include both applied state and live state.
The evidence should answer an operator’s next question
Weak vulnerability evidence says:
CVE present. Update package.
That might be useful before patching. It is less useful after the patch window, especially if the package was already updated.
Better evidence says:
Package openssl-libs is fixed on disk, but nginx still maps the old libssl object.
Restart nginx and re-check process maps.
Or:
Fixed kernel package is installed, but the host is still running the previous kernel.
Reboot the host and verify uname -r afterward.
Or:
Package is fixed on disk and no stale runtime mapping was detected.
No further host action from this finding.
Those are different outcomes. They go to different owners. They have different operational risk. They should not be collapsed into the same “patched” bucket.
The best evidence helps the operator decide what to do next:
- update a package
- restart a service
- reboot a host
- review exposure or ownership
- close the finding
That is the difference between a scanner queue and a remediation queue.
Minimum host evidence worth collecting
For a Linux vulnerability closure, I want the evidence to be boring, repeatable, and clear enough that someone else can read it later without reconstructing the whole patch window.
At minimum, collect these fields.
host
checked_at_utc
os_release
running_kernel
package_name
installed_evr
vendor_fixed_evr
cve_or_advisory
severity
runtime_evidence
service_or_process_context
recommended_action
verification_result
Not every field applies to every finding, but the shape matters.
Host and timestamp
Start with identity and time. It sounds obvious until you are looking at three screenshots from three different terminals.
hostname
date -u +%Y-%m-%dT%H:%M:%SZ
cat /etc/os-release
For closure evidence, I also like having the running kernel visible:
uname -r
uname -a
The timestamp matters because evidence goes stale. A host that was clean at 01:00 UTC may not be clean after a rollback, failed reboot, package downgrade, or later deployment.
Installed package EVR
For RHEL-family systems, package evidence should include the installed epoch/version/release, not just the upstream version string.
Example:
rpm -q openssl-libs
rpm -qi openssl-libs
The EVR matters because enterprise Linux vendors backport security fixes. A package can look old compared with upstream while still containing the vendor fix. Naive version checks create noisy evidence.
The question is not only:
Is this upstream version new?
It is:
Does this installed vendor package contain the fixed build for this distro?
That means the evidence should preserve the distro context and the vendor-fixed EVR when possible.
Vendor-fixed EVR or advisory context
If a package is marked vulnerable, the evidence should say what “fixed” means for that operating system.
Useful fields:
cve: CVE-2024-1086
package: kernel
installed_evr: 5.14.0-427.el9
vendor_fixed_evr: 5.14.0-503.el9
source: vendor advisory / OVAL / security metadata
This avoids the common argument where one tool compares upstream versions, another tool understands vendor backports, and the operator is stuck explaining why 3.0.7 may or may not be fixed depending on the release.
Good evidence should make that interpretation explicit.
Running kernel state
Kernel findings need a live-state check.
The installed kernel packages tell you what the host can boot into. The running kernel tells you what the host is actually using right now.
uname -r
rpm -q --last kernel-core 2>/dev/null | head -1
If the fixed kernel package is installed but uname -r still shows the old kernel, the host is not clean yet. It may be waiting on a maintenance window. It may be waiting on cluster drain. It may be blocked for a good reason.
But it should not be marked remediated without saying:
required_action: reboot host
verification: compare running kernel after reboot
That small distinction saves a lot of false closure.
Stale mapped libraries
Shared library issues are where evidence gets more interesting.
A process can keep using a file after the package manager replaced or removed it. That is normal Linux behavior. It is also why “fixed on disk” does not always mean “fixed live.”
A rough inspection pass:
sudo grep -H '(deleted)' /proc/[0-9]*/maps 2>/dev/null | \
grep -E '/(usr/)?lib(64)?/.*\.so'
Or:
sudo lsof +L1
These commands are not a full vulnerability assessment. They are evidence sources. You still need to map the object back to a package, CVE, fixed EVR, and process context.
A useful finding should look more like:
package: openssl-libs
applied_state: fixed package installed
live_state: nginx worker still maps old deleted libssl object
affected_pids: 1842, 1843, 1844
required_action: restart nginx
verification: re-check process maps after restart
That is far more useful than “OpenSSL vulnerable” after the patch already ran.
Service and exposure context
Runtime evidence gets more actionable when it tells you what owns the process.
For a PID:
ps -fp <pid>
For listeners:
sudo ss -tulpn
If a stale library is mapped by a service bound to 0.0.0.0:443, that deserves different urgency than a stale mapping in a short-lived internal batch job. If the process is not network-facing but handles sensitive data, that still matters. If the process is going to exit naturally in five minutes, maybe the same escalation is not needed.
The point is not to turn every stale mapping into an emergency.
The point is to stop losing the service context.
Useful evidence buckets
After collecting host evidence, most findings should land in one of a few buckets.
1. Package update required
The installed package is below the vendor-fixed EVR.
Evidence should include:
installed_evr
vendor_fixed_evr
cve_or_advisory
recommended_package_action
This is the classic patch case. The next action is still an update.
2. Service restart required
The fixed package is on disk, but a running process still maps old code.
Evidence should include:
package fixed on disk
stale mapped object
pid / command / service
recommended restart target
verification command
This is the case that often disappears into tribal knowledge. It should be first-class closure evidence.
3. Host reboot required
The fixed kernel is installed, but the host is still booted into the old kernel.
Evidence should include:
running_kernel
newest_installed_kernel
fixed_kernel_evr
recommended reboot action
post-reboot verification
This is not “patch failed.” It is “patch follow-through still pending.”
4. Manual review required
The package is present or the evidence is incomplete, but the real risk depends on exposure, reachability, ownership, or workload behavior.
Evidence should say what is missing:
unknown service owner
port exposure unclear
container boundary needs review
host has not reported recently
package ownership could not be confirmed
This is better than pretending the finding is clean or leaving everyone to guess.
5. Verified fixed
The package is fixed and the runtime evidence does not show the vulnerable code still live.
Evidence should include:
installed fixed package
runtime check result
verification timestamp
This is the bucket everyone wants. It should be earned by evidence, not assumed from package state alone.
A copyable vulnerability closure template
When a vulnerability needs Linux host evidence, this is the shape I want in the closure record, assessment notes, remediation summary, or whatever process the team uses.
Host:
Checked at UTC:
OS / distro:
Running kernel:
CVE / advisory:
Affected package:
Installed EVR:
Vendor-fixed EVR:
Applied state:
Live state:
Service / process context:
Exposure context:
Recommended action:
Verification performed:
Result:
Notes / exceptions:
Example:
Host: rhel-app-01
Checked at UTC: 2026-07-09T03:14:22Z
OS / distro: Rocky Linux 9.4
Running kernel: 5.14.0-427.el9.x86_64
CVE / advisory: CVE-2024-1086
Affected package: kernel
Installed EVR: 5.14.0-503.el9
Vendor-fixed EVR: 5.14.0-503.el9
Applied state: fixed kernel package installed
Live state: host is still running 5.14.0-427.el9.x86_64
Service / process context: kernel
Exposure context: production app host
Recommended action: reboot host into fixed kernel during approved window
Verification performed: uname -r compared with installed kernel package
Result: reboot required before closure
Notes / exceptions: coordinate reboot with app owner
That is not a novel. It is enough context for an engineer, a security lead, or a compliance reviewer to understand why the vulnerability is or is not ready to close.
Be honest about what the evidence does not prove
Good evidence is specific, but it should not overclaim.
A deleted mapped library does not automatically prove exploitable risk. You still need package and CVE context.
No deleted mapping does not prove a host is perfectly safe. It only says that particular runtime signal was not found.
A fixed vendor package may still look “old” if someone compares it to upstream without understanding backports.
Containerized workloads can complicate the view. Host package state, image contents, mounted filesystems, namespaces, and process ownership all matter.
Compliance evidence is similar. A clean host-level report can support a CIS, DISA STIG, CMMC, PCI, or HIPAA workflow, but it is not the same thing as an attestation. Scope and interpretation still belong with the team, assessor, or compliance advisor responsible for the program.
That caution is not weakness. It is what makes the evidence credible.
The useful end state
The best post-patch evidence is not dramatic. It is plain and hard to argue with.
This host needs a package update.
This host needs nginx restarted.
This host needs a reboot.
This host needs review because the exposed service owner is unknown.
This host is verified fixed at this timestamp.
Those statements are operational. They tell people what to do. They also tell security and compliance what proof exists.
That is the level of clarity Linux teams deserve before a vulnerability is closed.
The goal is not to make patching feel heavier.
The goal is to make closure mean something.
If you want to see this model as a report, the sample Patch Truth report shows the same idea in artifact form. For a supported RHEL-family host, the one-host snapshot is the quick way to test the evidence path on a real system.