VYPR
Moderate severityOSV Advisory· Published Jan 12, 2026· Updated Jan 13, 2026

hermes's raw options logging may disclose secrets passed in via subcommand options argument

CVE-2026-22798

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.

PackageAffected versionsPatched versions
hermesPyPI
>= 0.8.1, < 0.9.10.9.1

Affected products

1

Patches

2
90cb86acd026

Merge commit from fork

https://github.com/softwarepub/hermesStephan DruskatJan 12, 2026via ghsa
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
    
7f64f102e916

Add basic error handling to console entry point

https://github.com/softwarepub/hermesMeinel, MichaelAug 6, 2024via ghsa
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

News mentions

0

No linked articles in our index yet.