hermes's raw options logging may disclose secrets passed in via subcommand options argument
Description
hermes is an implementation of the HERMES workflow to automatize software publication with rich metadata. From 0.8.1 to before 0.9.1, hermes subcommands take arbitrary options under the -O argument. These have been logged in raw form. If users provide sensitive data such as API tokens (e.g., via hermes deposit -O invenio_rdm.auth_token SECRET), these are written to the log file in plain text, making them available to whoever can access the log file. This vulnerability is fixed in 0.9.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
hermesPyPI | >= 0.8.1, < 0.9.1 | 0.9.1 |
Affected products
1Patches
290cb86acd026Merge commit from fork
4 files changed · +35 −1
CHANGELOG.md+4 −0 modified@@ -31,6 +31,10 @@ and this project tries to adhere to [Semantic Versioning](https://semver.org/spe - Update poetry to more recent version. (#347) +### Security + +- Patch raw logging of '-O' values that could have included arbitrary secrets. (https://github.com/softwarepub/hermes/security/advisories/GHSA-jm5j-jfrm-hm23) + ## [0.9.0] - 2025-02-26 ### Added
src/hermes/commands/cli.py+2 −1 modified@@ -16,6 +16,7 @@ HermesHarvestCommand, HermesProcessCommand, HermesCurateCommand, HermesDepositCommand, HermesPostprocessCommand, HermesInitCommand) from hermes.commands.base import HermesCommand +from hermes.utils import mask_options_values def main() -> None: @@ -63,7 +64,7 @@ def main() -> None: logger.init_logging() log = logger.getLogger("hermes.cli") - log.debug("Running hermes with the following command line arguments: %s", args) + log.debug("Running hermes with the following command line arguments: %s", mask_options_values(args)) try: log.debug("Loading settings...")
src/hermes/utils.py+23 −0 modified@@ -8,6 +8,7 @@ from importlib.metadata import metadata from mimetypes import guess_type from pathlib import Path +import argparse def retrieve_project_urls(metadata_urls: list[str]) -> dict[str, str]: @@ -80,3 +81,25 @@ def guess_file_type(path: Path): # use non-strict mode to cover more file types return guess_type(path, strict=False) + +def mask_options_values(args: argparse.Namespace) -> argparse.Namespace: + """Masks potentially sensitive values in the 'options' argument + in the passed argparse.Namespace. + + The main use case for this is preventing potentially sensitive + data/secrets being included in raw args logging. + + :param args: The argparse.Namespace to mask. + :return: A copy of the namespace with masked sensitive values. + """ + import copy + + masked_args = copy.copy(args) + + # Mask the values for 'options' if they exist + if hasattr(masked_args, "options") and masked_args.options: + masked_args.options = [ + (key, "***REDACTED***") for key, value in masked_args.options + ] + + return masked_args
test/hermes_test/test_utils.py+6 −0 modified@@ -5,6 +5,7 @@ import toml from pathlib import Path +from argparse import Namespace pyproject = toml.load(Path(__file__).parent.parent.parent / "pyproject.toml") expected_name = pyproject["project"]["name"] @@ -22,3 +23,8 @@ def test_hermes_user_agent(): assert ( hermes_user_agent == f"{expected_name}/{expected_version} ({expected_homepage})" ) + +def test_mask_values_options(): + from hermes.utils import mask_options_values + ns = Namespace(foo="bar", options=[("foo", "bar"), ("bar", "foo")]) + assert mask_options_values(ns) == Namespace(foo="bar", options=[("foo", "***REDACTED***"), ("bar", "***REDACTED***")]) \ No newline at end of file
7f64f102e916Add basic error handling to console entry point
1 file changed · +19 −3
src/hermes/commands/cli.py+19 −3 modified@@ -9,6 +9,7 @@ This module provides the main entry point for the HERMES command line application. """ import argparse +import sys from hermes import logger from hermes.commands import HermesHelpCommand, HermesCleanCommand, HermesHarvestCommand, HermesProcessCommand, \ @@ -58,7 +59,22 @@ def main() -> None: args = parser.parse_args() logger.init_logging() + log = logger.getLogger("hermes.cli") + log.debug("Running hermes with the following command line arguments: %s", args) - args.command.load_settings(args) - args.command.patch_settings(args) - args.command(args) + try: + log.info("Loading settings...") + args.command.load_settings(args) + + log.debug("Update settings from command line...") + args.command.patch_settings(args) + + log.info("Run subcommand %s", args.command.command_name) + args.command(args) + except BaseException as e: + log.error("An error occurred during execution of %s", args.command.command_name) + log.debug("Original exception was: %s", e) + + sys.exit(1) + + sys.exit(0)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-jm5j-jfrm-hm23ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-22798ghsaADVISORY
- github.com/softwarepub/hermes/commit/7f64f102e916c76dc44404b77ab2a80f5a4e59b1ghsax_refsource_MISCWEB
- github.com/softwarepub/hermes/commit/90cb86acd026e7841f2539ae7a1b284a7f263514ghsax_refsource_MISCWEB
- github.com/softwarepub/hermes/security/advisories/GHSA-jm5j-jfrm-hm23ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.