The whole point of marking a parameter sensitive in Puppet is that Puppet keeps the value out of its logs, reports, and saved state. On affected versions, that promise quietly broke. Passwords and other secrets pushed through the Resource API, the framework module authors use to build custom resource types, were written in the clear into the state record Puppet saves on every managed node's local disk. The flaw is CVE-2026-8804, disclosed on July 3, 2026 by Perforce, which owns Puppet.
It carries a CVSS 4.0 score of 6.7 (medium), and no exploitation or public proof-of-concept has been reported. That label describes how hard the data is to reach, not how many places the secret ended up. Read it as an at-rest exposure problem rather than a remote-takeover bug, and the priority gets clearer.
What broke: Puppet stopped masking the secrets it was told to hide
Puppet lets a module tag a parameter as sensitive so the value never shows up in cleartext in logs, reports, or saved run data. The Resource API is the modern way to author custom resource types, and on the affected releases it dropped that tag. A value the module meant to protect, a database password, an API token, a service credential, then landed in plaintext inside the state record each agent writes to local disk after a run, rather than being masked. Puppet files this under two weakness classes, CWE-312 and CWE-313, for keeping a secret unencrypted on disk.
The exposure sits on the node, not the primary server. Every machine running an affected agent that applied such a type now holds the plaintext value in its state cache. Per the CVSS vector, reading it costs an attacker local access with high privileges (AV:L, PR:H), which is why the score lands at medium. But the entire value of a masking control is that it shrinks where a secret can be found. When it silently fails, the opposite happens: the secret spreads to node backups, golden images, and any log or forensic collection that sweeps up the state directory. A masking control that fails quietly is worse than none, because teams built their secret handling on the assumption that it worked.
Which versions are affected
The bug lives in the Puppet resource_api module versions 1.5.0 through 1.9.1 and version 2.0.0. It shipped inside Puppet Core 8.0.0 through 8.19.0, and Puppet Enterprise 2023.8.0 through 2023.8.9 and 2025.0.0 through 2025.10.0. It is fixed in resource_api 1.9.2 and 2.0.1, which ship with Puppet Core 8.20.0, Puppet Enterprise 2023.8.10, and Puppet Enterprise 2025.11.0.
| Component | Affected | Fixed in |
|---|---|---|
| Puppet resource_api module | 1.5.0 - 1.9.1 and 2.0.0 | 1.9.2 and 2.0.1 |
| Puppet Core | 8.0.0 - 8.19.0 | 8.20.0 |
| Puppet Enterprise 2023.8 | 2023.8.0 - 2023.8.9 | 2023.8.10 |
| Puppet Enterprise 2025 | 2025.0.0 - 2025.10.0 | 2025.11.0 |
Patch is step one. Rotating the exposed secrets is step two.
Upgrading closes the leak going forward: fixed agents stop writing sensitive values in cleartext. It does nothing about the values already sitting in state caches across your fleet, and it cannot un-expose a credential that has already been copied off a node in a backup or an image. Treat this as a secret-exposure incident scoped to the window an affected version was running, not a patch-and-forget CVE. We made the same argument when Gravity SMTP leaked live email API keys: the fix stops new exposure, but a secret that has already leaked stays compromised until you rotate it. Concretely:
- Upgrade to a fixed release: resource_api 1.9.2 or 2.0.1, or the Puppet Core / Enterprise version that bundles it (8.20.0, 2023.8.10, or 2025.11.0).
- Inventory your exposure. You are affected only if you run custom types built on the Resource API that define sensitive parameters. If you do not write or use such types, the plaintext-in-state problem does not apply to you.
- Find the state directory on each node with
puppet config print statedir, then clear the stale transaction state cache so the plaintext values are not left behind after the upgrade. - Rotate every credential that flowed through a sensitive Resource API parameter while an affected version ran. Assume it was exposed at rest, because it was.
- Check the blast radius beyond live nodes: backups, snapshots, and golden images taken during the affected window carry the same plaintext and need the same rotation decision.
The severity math is honest, but it hides the operational point. This is not a bug an attacker fires across the internet. It is a control you relied on that stopped working, on every node you manage, without an error. The patch is easy. Knowing which secrets to rotate is the actual work, and only you can scope it.