Remediating 18 OpenSSL CVEs at Scale with Puppet Puppet has published guidance on remediating 18 OpenSSL vulnerabilities at scale using its infrastructure automation platform. The June 2026 advisory includes a high-severity heap use-after-free bug in PKCS7_verify() that can lead to remote code execution, with six of the CVEs credited to Anthropic's Mythos model and researcher Alex Gaynor. PuppetDB queries can identify affected nodes, and Puppet tasks or code can enforce patching across large fleets. Written by Paul Reed . The June 2026 OpenSSL advisory is a big one. 18 vulnerabilities, one rated high severity https://www.puppet.com/blog/openssl-cve-2026-45447-patching with remote code execution potential, and a disclosure credited in part to Anthropic's Mythos model https://red.anthropic.com/2026/mythos-preview/ working alongside researcher Alex Gaynor. Six of those CVEs trace back to that collaboration. If you manage infrastructure at scale, here is how to scope your exposure and get patched cleanly. CVE-2026-45447 is a heap use-after-free in PKCS7 verify . The bug fires when OpenSSL processes a PKCS 7 or S/MIME signed message where the SignedData.digestAlgorithms field is an empty ASN.1 SET. When that happens, OpenSSL frees a BIO object that was passed in by the calling application and is still expected to be valid. The calling application then uses the freed pointer. Depending on heap layout, that results in heap corruption, a process crash, or with a controlled heap grooming primitive, code execution. Affected ranges: The other 17 CVEs in the advisory cover authentication bypass via forged certificates moderate, ~1-in-256 success rate , ciphertext forgery, private key recovery, root CA replacement, and several DoS vectors. None are trivial in regulated environments. Before touching anything, you want a precise list of affected nodes. PuppetDB gives you this directly from agent-reported facts. No scanner, no spreadsheet, no guessing. puppet query 'inventory certname, facts.os.name, facts.os.release.full, facts.openssl version { facts.openssl version ~ "^ 3\. 0-3 \.|1\. 0-1 \. " and facts.openssl version = absent }' This returns every managed node reporting a vulnerable OpenSSL version, along with OS name, release, and the installed version string. Pipe it to jq for filtering: puppet query 'inventory certname, facts.openssl version, facts.environment { facts.openssl version ~ "^ 3\. 0-3 \.|1\. 0-1 \. " }' | jq '. | select .facts.environment == "production" ' You now have your production blast radius in seconds. There are two approaches depending on what you need: an immediate one-time push, or ongoing enforced state. For an immediate patch across a set of nodes, the built-in package task gets it done without any code changes: puppet task run package action=upgrade name=openssl --nodes node1,node2,node3 For scale, run the task through the Puppet Enterprise GUI and target an entire node group at once. Concurrency limits apply, so large fleets roll out in controlled waves automatically. This is the fastest path when you need to push now and sort out the code side later. For ongoing enforcement through Puppet code, a simple package resource is all you need. No additional module required. js package { 'openssl': ensure = latest, or pin to the specific version: '3.5.1' } If you want to lock to the exact patched version rather than latest — which is the safer choice for production since it keeps change controlled — set the version string directly: js package { 'openssl': ensure = '3.5.1', } Add this to an existing profile class your nodes already include. No new module, no new class hierarchy, no Hiera restructuring. If services need to restart after the library updates, wire in a notify relationship: js package { 'openssl': ensure = '3.5.1', notify = Service 'nginx' , } The notify fires the service restart only after the package actually changes. If the package is already at the right version on the next run, no restart fires. That matters for services where unnecessary restarts are disruptive. Create or update a security::openssl class. The core pattern is simple: declare the required package version in Hiera, look it up in the manifest, and subscribe dependent services to the package resource so they restart automatically after the library is replaced. site-modules/security/manifests/openssl.pp class security::openssl String $version = lookup 'security::openssl::version' , { package { 'openssl': ensure = $version, } Debian/Ubuntu ships libssl separately if $facts 'os' 'family' == 'Debian' { package { 'libssl-dev': ensure = $version, } } RHEL/Rocky/Alma ships openssl-libs if $facts 'os' 'family' == 'RedHat' { package { 'openssl-libs': ensure = $version, } } Services that need to restart when OpenSSL updates Package 'openssl' ~ Service 'nginx' Package 'openssl' ~ Service 'apache2' Package 'openssl' ~ Service 'postfix' Package 'openssl' ~ Service 'sshd' } Pin the version in Hiera. Using a version string rather than latest gives you reproducible, auditable rollouts. data/common.yaml security::openssl::version: '3.5.1' Want to vary by OS family? Layer your Hiera: data/os/RedHat.yaml security::openssl::version: '3.5.1-2.el9' data/os/Debian.yaml security::openssl::version: '3.5.1-1ubuntu1' A successful package upgrade does not guarantee the running process is using the new library. Services that were already loaded before the update still have the old .so mapped in memory until they restart. Confirm post-patching with lsof : sudo lsof -p $ pgrep nginx | head -1 | grep libssl Or simply check the installed version: openssl version If lsof still shows the old library path after Puppet ran, check whether the service restart fired by reviewing the Puppet agent log on that node. After the rollout, run a follow-up PuppetDB query to verify closure. This also doubles as audit evidence. puppet query 'inventory certname, facts.openssl version, facts.environment { facts.openssl version ~ "^ 3\. 0-3 \.|1\. 0-1 \. " }' | jq length That number should be zero. If it is not, you have a precise list of which nodes still need attention. Puppet Enterprise users can pull this same data from the compliance dashboard and export it directly for audit review. The puppet/openssl Forge module is a legitimate tool for managing PKI entities — keys, CSRs, certificates, DH parameters. If you are already using it for those purposes, there is nothing wrong with it. For this specific advisory though, it is more than you need. Patching the OpenSSL package is a one-resource job. Pulling in an additional module to do what package { 'openssl': ensure = '3.5.1' } handles natively adds complexity without benefit. Keep it simple. Puppet manages the host OS. If your containers bundle their own OpenSSL, you need to rebuild and redeploy those images. PuppetDB facts can help you identify which hosts are running containers that may have bundled the library, but the remediation path is a container pipeline problem, not a package manager problem. Use Puppet's scheduled tasks or a maintenance window tag in your node group rules to defer the restart to an approved window. The package can update immediately; the service restart can be deferred. This is a better posture than delaying the package update itself. Defer restarts to a maintenance window using a fact class security::openssl deferred restart { package { 'openssl': ensure = '3.5.1', } Only restart if we are in the declared maintenance window if $facts 'maintenance window' == true { Package 'openssl' ~ Service 'nginx' } } If you are running OpenSSL 1.0.x or an OS that ships a version, the vendor no longer patches, this advisory is a forcing function. A one-time patch run is not the goal. The goal is a permanent change to your security posture. You configure scan frequency – 48X per day by default – Puppet enforces desired state. If a node drifts back to a vulnerable OpenSSL version, whether because of a failed package hold, a reprovisioned VM built from an old image, or a manual change someone made and forgot about, Puppet corrects it on the next run without a ticket or a human in the loop. For a vulnerability class that attackers are actively targeting within hours of disclosure, that continuous enforcement posture is the actual protection. The patch run will fix the issue one time, continuous enforcement with Puppet keeps you there.