Jan 17, 2026·5 min read·30 visits
RustFS versions prior to 1.0.0-alpha.80 log the shared HMAC secret when an RPC signature verification fails. This allows attackers with read access to logs to steal the key and gain full control over the storage cluster. The fix involves redacting the secret from error messages.
A classic case of 'debug mode left on in production' affects RustFS, a distributed object storage system. By handling authentication failures too verbosely, the system writes the master HMAC secret directly to the server logs. An attacker with log access—common in modern cloud environments—can retrieve this key and forge valid signatures for any administrative action.
In the world of distributed systems, we often obsess over encryption in transit, encryption at rest, and fancy key management services. We build Fort Knox, install retina scanners, and hire armed guards. Then, just to be helpful, we tape the combination code to the forehead of the guard standing outside.
That is essentially what happened with RustFS, a distributed object storage system built in Rust. In an attempt to make debugging authentication errors easier, the developers inadvertently created a mechanism that dumps the keys to the kingdom straight into the system logs. This isn't a complex heap overflow or a race condition; it's a logic error born of good intentions and bad OpSec.
While the CVSS score sits at a deceptive 'Low' (2.9)—primarily because the attacker needs access to logs—anyone who has worked in a DevOps environment knows that kubectl logs permissions are handed out like candy. If your logs are shipped to ELK, Datadog, or Splunk, that 'Low' severity quickly transforms into a 'Critical' nightmare.
The vulnerability lives in crates/ecstore/src/rpc/http_auth.rs, specifically within the signature verification logic. RustFS uses HMAC (Hash-based Message Authentication Code) to verify that Remote Procedure Calls (RPCs) are legitimate. The server calculates an expected_signature using a shared secret and compares it to the incoming request's signature.
So far, so good. But what happens when they don't match? In a secure system, the server should return a generic 401 or 403 error. Maybe log 'Signature verification failed for user X'.
In RustFS, the code decided to be extremely helpful. It thought, "Hey, if the signatures don't match, the developer probably wants to know why." So, it logged everything involved in the calculation. Everything. Including the secret itself. It's the cryptographic equivalent of a bank teller shouting your PIN out loud because you typed it wrong the first time.
Let's look at the diff. It's rare to see a vulnerability so obvious that it makes you wince physically. Here is the vulnerable logic in verify_rpc_signature:
// The Vulnerable Logic
if signature != expected_signature {
error!(
"verify_rpc_signature: Invalid signature: secret {}, url {}, method {}, timestamp {}, signature {}, expected_signature {}",
secret, // <--- OOPS.
url,
method,
timestamp,
signature,
expected_signature
);
return Err(std::io::Error::other("Invalid signature"));
}The fix, implemented in commit 6b2eebee1d07399ef02c0863bd515b4412a5a560, is straightforward: stop logging the secret. The developers also realized that logging the full expected_signature allows for offline brute-forcing or verification of the secret, so they masked that too.
// The Fix
if signature != expected_signature {
error!(
"verify_rpc_signature: Invalid signature: url {}, method {}, timestamp {}, signature {}, expected_signature: {}***{}|{}",
url,
method,
timestamp,
signature,
// Masking the expected signature to show only start/end chars
expected_signature.chars().next().unwrap_or('*'),
expected_signature.chars().last().unwrap_or('*'),
expected_signature.len()
);
return Err(std::io::Error::other("Invalid signature"));
}As a bonus, they also caught a similar issue in rustfs/src/config/mod.rs. The configuration struct Opt was using a default #[derive(Debug)]. When the app started up or crashed, it would pretty-print the entire configuration state, including secret_key and kms_vault_token. They replaced this with a manual fmt::Debug implementation that sanitizes these fields.
Exploiting this requires zero coding skill and only basic access privileges (specifically, the ability to read logs). The attack flow is embarrassingly simple:
error! macro.docker logs). Look for the string "verify_rpc_signature".secret from the log entry.Once the attacker has the HMAC secret, they are effectively a super-admin. They can sign requests to read files, delete volumes, or reconfigure the cluster. The system cannot distinguish them from a legitimate node.
The CVSS 4.0 score of 2.9 (Low) is technically correct because the vulnerability requires "Attack Requirements: Present" (access to logs). However, in the real world, this score is dangerous. It assumes that logs are treated as highly sensitive data, which is rarely the case.
In modern microservices architectures, logs are often piped to third-party services, viewed by junior developers, or stored in S3 buckets with permissive read policies. If an internal bad actor or a compromised developer account can read logs, they can escalate from "read-only access to logs" to "full read/write access to the storage cluster."
Furthermore, because this is an HMAC secret, it's likely a long-lived static key. Unless the organization has automated secret rotation (unlikely if they are using static HMAC keys), this leaked credential could remain valid for years.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:P| Product | Affected Versions | Fixed Version |
|---|---|---|
RustFS RustFS | >= 1.0.0-alpha.1, < 1.0.0-alpha.80 | 1.0.0-alpha.80 |
| Attribute | Detail |
|---|---|
| CWE | CWE-532 (Insertion of Sensitive Information into Log File) |
| Attack Vector | Network (Trigger) / Local or Network (Log Access) |
| CVSS 4.0 | 2.9 (Low) |
| Impact | Full System Compromise (via Credential Theft) |
| Affected Component | crates/ecstore/src/rpc/http_auth.rs |
| Exploit Complexity | Trivial |
The software writes sensitive information to a log file, which can allow an attacker to obtain the information by reading the log.
An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.
A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.
OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.
An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.
A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.
An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.