Feb 19, 2026·6 min read·12 visits
Hermes versions 0.8.1 to <0.9.1 log command-line arguments in plaintext, including secrets passed via the '-O' flag. Attackers with access to log files (e.g., CI/CD artifacts) can harvest API tokens. Fixed in v0.9.1.
A classic case of 'logging too much,' CVE-2026-22798 reveals how the Hermes workflow automation tool accidentally documented its own secrets. By dumping the full command-line argument namespace into debug logs, the application exposed sensitive API tokens (like Invenio RDM authentication credentials) in plaintext. This vulnerability turns standard CI/CD build artifacts into a goldmine for attackers seeking lateral movement.
In the world of DevOps and scientific publishing, automation is king. We build tools to move data from Point A to Point B without human intervention. Enter hermes, a workflow tool designed to automate software publication with rich metadata. It connects to platforms like Invenio RDM, handling the heavy lifting of metadata curation and deposition.
But automation tools need keys to the kingdom. They need API tokens, authentication secrets, and specialized configurations to talk to these remote repositories. In hermes, these secrets are often passed via the command line options.
Here lies the problem: Developers love logs. We love them. We want to know exactly what our code is doing at every split second. But there is a fine line between 'helpful debugging information' and 'accidentally writing your PIN code on a billboard.' CVE-2026-22798 is a textbook example of crossing that line. It’s not a buffer overflow or a complex heap grooming exploit; it’s the application simply telling the log file secrets it promised to keep.
The root cause of this vulnerability is a fundamental misunderstanding—or perhaps just a moment of carelessness—regarding how Python's argparse library handles object representation.
In src/hermes/commands/cli.py, the application accepts command-line arguments to control its behavior. One of these arguments is -O (or --options), used to pass dynamic configuration values, including sensitive data like invenio_rdm.auth_token.
When the application starts, it parses these arguments into a Namespace object. The developer, likely intending to make debugging easier, decided to log this object:
# The culprit in src/hermes/commands/cli.py
log.debug("Running hermes with the following command line arguments: %s", args)Here is the catch: argparse.Namespace objects have a default __repr__ method that returns a string containing all attributes and their values. It does not discriminate. It does not redact. If you pass a token, that token becomes part of the string. The application then dutifully writes that string to hermes.log.
This is a CWE-532 (Insertion of Sensitive Information into Log File) at its purest. It’s functionally equivalent to print(password).
Let's look at the fix. The remediation didn't require re-architecting the authentication flow; it just required a muzzle for the logger.
The maintainers introduced a sanitization utility in src/hermes/utils.py. This function takes the arguments, creates a copy (to avoid modifying the actual runtime variables), and explicitly overwrites the sensitive options list with a placeholder string.
Here is the logic introduced in commit 90cb86acd026e7841f2539ae7a1b284a7f263514:
def mask_options_values(args: argparse.Namespace) -> argparse.Namespace:
import copy
masked_args = copy.copy(args)
# Check if we have options to mask
if hasattr(masked_args, "options") and masked_args.options:
# Overwrite the value in the tuple (key, value)
masked_args.options = [
(key, "***REDACTED***") for key, value in masked_args.options
]
return masked_argsThen, in the CLI entry point (src/hermes/commands/cli.py), they wrapped the logging call:
Vulnerable:
log.debug("Running hermes with the following command line arguments: %s", args)Patched:
log.debug("Running hermes with the following command line arguments: %s", mask_options_values(args))This ensures that while the application still functions with the real secrets, the persistent log record only sees ***REDACTED***. It’s a simple, effective patch, though one that highlights how manual data sanitization is often an afterthought.
How does a hacker exploit this? They likely don't need a shell on the production server immediately. They just need access to the artifacts.
hermes is a workflow tool, which means it likely runs inside CI/CD pipelines (GitHub Actions, GitLab CI, Jenkins). These environments typically archive logs to help developers troubleshoot failed builds.
The Attack Chain:
hermes for publication. They gain read access to the build logs (e.g., as a junior developer, or via a misconfigured public Jenkins instance).hermes.log or views the console output of a previous run.auth_token or just scanning the Running hermes... lines reveals the plaintext credentials.$ grep -r "invenio_rdm.auth_token" ./build_logs/
hermes.log: DEBUG: Running hermes... Namespace(..., options=[('invenio_rdm.auth_token', 'eyJhbGciOiJIUz...'), ...])eyJ... token and authenticates directly against the Invenio RDM instance, bypassing the CI/CD controls entirely to modify, delete, or poison research data.> [!NOTE] > While the CVSS score is 'Medium' (5.9) due to the requirement of local/file access, in a modern DevSecOps environment, "local file access" to logs is often granted to hundreds of developers. The blast radius is wider than the vector suggests.
There is a strange discrepancy in the official reporting for this CVE. The NVD and GitHub Advisory vectors list Confidentiality impact as None (C:N) but Integrity impact as High (I:H).
Technically, this is absurd. The vulnerability is literally an information disclosure (Confidentiality loss). However, if we play devil's advocate, the scorer might be focusing on the outcome of the stolen token: using it to forge or modify data on the target repository (Integrity loss).
Regardless of how the bureaucracy scores it, the impact is clear:
hermes is used to publish software packages, a stolen token could allow an attacker to upload malicious versions of libraries, affecting downstream users.If you are using hermes anywhere in your stack, patching the binary is only step one.
1. Upgrade: Move to version 0.9.1 immediately. This stops the bleeding.
2. Rotate Credentials: This is the critical step most teams forget. Any token that has ever been passed to hermes in a vulnerable version must be considered compromised. Revoke the old tokens and issue new ones.
3. Purge Artifacts: Go back through your CI/CD history and delete old log files. If you have a centralized logging server (Splunk, ELK, Datadog), you need to scrub those indexes too. A patched application doesn't fix a log file from three months ago that's still sitting in an S3 bucket.
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
hermes softwarepub | >= 0.8.1, < 0.9.1 | 0.9.1 |
| Attribute | Detail |
|---|---|
| CWE | CWE-532 (Insertion of Sensitive Information into Log File) |
| CVSS v3.1 | 5.9 (Medium) |
| Attack Vector | Local (File Read) |
| Integrity Impact | High (via Stolen Credentials) |
| Confidentiality Impact | None (Official Vector) / High (Real World) |
| Exploit Status | No Known Public Exploit |
| Patch Commit | 90cb86acd026e7841f2539ae7a1b284a7f263514 |
The application writes sensitive information to a log file, where it may be disclosed to unauthorized parties.