CVE-2026-22798

Loose Lips Sink Ships: How Hermes Logged Its Way into a Security Nightmare

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 14, 2026·4 min read

Executive Summary (TL;DR)

Developers often log too much in the name of debugging. In CVE-2026-22798, the `hermes` CLI tool dumped the entire `argparse` namespace into a log file. Since `hermes` allows passing secrets via the `-O` flag, this meant every API key used to publish software was written to disk in plaintext. If you share a machine or run this in CI/CD, your secrets are public property.

The hermes software publication tool inadvertently logged sensitive command-line arguments, including API tokens and authentication secrets, to plaintext log files due to overzealous debug logging.

The Hook: The Road to Hell is Paved with Debug Logs

There is an old adage in software engineering: "If it isn't in the logs, it didn't happen." Developers love logs. We crave the sweet validation of a timestamped string telling us exactly what our code is doing. But there is a fine line between helpful instrumentation and inadvertently creating a diary of your deepest, darkest secrets.

hermes is a tool designed to automate the boring parts of software publication. It talks to platforms like InvenioRDM and Zenodo, meaning it handles the keys to the kingdom: authentication tokens. These tokens are the digital equivalent of a signed blank check. You pass them to hermes, and hermes does the heavy lifting.

But in versions 0.8.1 through 0.9.0, hermes was a bit of a gossip. In an effort to be helpful during debugging, it decided to write down everything you told it. And I mean everything. This is the story of how a single line of Python transformed a helpful utility into a credential-leaking machine.

The Flaw: Python's Chatty Namespaces

The root cause here isn't a buffer overflow or a complex race condition. It's a fundamental misunderstanding of how Python objects represent themselves as strings. The vulnerability lives in the main CLI entry point, where the application parses arguments using the standard argparse library.

When argparse parses command-line flags, it returns a Namespace object. This object holds all your flags as attributes. If you pass -O invenio_rdm.auth_token=s3cr3t, the namespace gets an options list containing that tuple.

The developers added a logging statement to capture the state of the application at startup. They essentially said, "Log the args object." The problem? The __repr__ (string representation) of a Namespace object is recursively exhaustive. It doesn't filter. It doesn't redact. It just spits out every attribute it holds. So, by logging the arguments to debug connection issues, they were simultaneously logging the very credentials needed to make those connections.

The Code: The Smoking Gun

Let's look at the crime scene. The vulnerability was introduced in commit 7f64f102e916c76dc44404b77ab2a80f5a4e59b1. Here is the vulnerable logic in src/hermes/commands/cli.py:

def main() -> None:
    # ... argument parsing setup ...
    args = parser.parse_args()
 
    logger.init_logging()
    log = logger.getLogger("hermes.cli")
    
    # THE VULNERABLE LINE
    log.debug("Running hermes with the following command line arguments: %s", args)

That %s formatting string is the betrayer. It invokes the string representation of args. If you ran a command like:

hermes deposit -O invenio_rdm.auth_token=MY_SUPER_SECRET_KEY

The log file (hermes.log) would happily record:

DEBUG: Running hermes with the following command line arguments: Namespace(..., options=[('invenio_rdm.auth_token', 'MY_SUPER_SECRET_KEY')], ...)

The fix, applied in commit 90cb86acd026e7841f2539ae7a1b284a7f263514, acknowledges the oopsie by introducing a sanitizer. They created a utility function mask_options_values that creates a copy of the arguments and replaces the sensitive values with ***REDACTED*** before logging.

The Exploit: Dumpster Diving in Logs

Exploiting this requires zero coding skills and 100% access to the filesystem (or the CI/CD console). It is a post-exploitation or insider threat scenario. Imagine you are a junior dev on a project using hermes in a shared Jenkins or GitHub Actions environment.

  1. Recon: You notice the build script runs hermes deposit with secrets injected from environment variables.
  2. The Attack: You don't have the environment variables, but you do have access to the build artifacts or the shared workspace where the runner executes.
  3. Execution: You simply open hermes.log.
grep "auth_token" hermes.log

Boom. You now have the production API keys for the organization's software repository. You can upload malicious packages, delete existing research data, or just cause general chaos. The CVSS score lists Confidentiality as 'None' because technically the vulnerability impacts the downstream system (Integrity of the repo), but practically speaking, you just lost your secrets.

The Fix: A Little Privacy, Please

The mitigation is straightforward: Upgrade hermes to version 0.9.1. The vendor patched this by sanitizing the log output. However, upgrading the software doesn't fix the past.

Crucial Cleanup Steps:

  1. Rotate Secrets: Assume every token ever used with hermes < 0.9.1 is compromised. Revoke them and issue new ones. Do this yesterday.
  2. Scrub Logs: Search your servers, CI runners, and backups for hermes.log. These files are now toxic waste. Delete them.
  3. Check Permissions: Why was the log file readable by others in the first place? Ensure your log directories have strict permissions (chmod 600 or similar) so that even if the application vomits secrets again, only root or the service user sees them.

Fix Analysis (2)

Technical Appendix

CVSS Score
5.9/ 10
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:N
EPSS Probability
0.01%
Top 99% most exploited

Affected Systems

hermes CLI tool (softwarepub)

Affected Versions Detail

Product
Affected Versions
Fixed Version
hermes
softwarepub
>= 0.8.1, < 0.9.10.9.1
AttributeDetail
CWE IDCWE-532
Attack VectorLocal (File Read)
CVSS5.9 (Medium)
EPSS Score0.00011 (Low)
ImpactCredential Leak / Integrity Compromise
Exploit StatusTrivial (Log Analysis)
CWE-532
Insertion of Sensitive Information into Log File

Insertion of Sensitive Information into Log File

Vulnerability Timeline

Vulnerable code introduced in commit 7f64f10
2026-01-01
Fix released in version 0.9.1 (approximate based on report)
2026-06-01

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.