PyPI / keyring / 25.7.0

keyring 25.7.0

Source
https://github.com/jaraco/keyring
Tag scanned
v25.7.0
Compared with
v25.6.0 (0 signals introduced since)
Files
52 scanned, 7 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 7 info
Scan time
6.1 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 5 of 5 warn and critical signals; 5 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-14 18:53

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. info warn → info by review dynamic-execution keyring/backend_complete.bash:8:3

    command name is a variable () not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

    	choices=$(
    		"${COMP_WORDS[0]}" --list-backends 2>/dev/null |
    			while IFS=$' \t' read -r backend rest; do
    				printf "%s\n" "$backend"
    likely benign LLM, confidence 0.90 Bash tab-completion helper that runs the invoked keyring command with --list-backends to gather backend names.
    Reasoning

    The command invoked is COMP_WORDS[0], the program the user is already typing, called with --list-backends to populate tab completion. This is the standard bash completion idiom. It runs only the user's own command, not a fixed or attacker-chosen payload, and the output is just printed names.

  2. info warn → info by review dynamic-execution keyring/backend_complete.zsh:12:14

    command name is a variable (`$words`) not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

    		choices+=(${${line/ \(priority: /\\\\:}/)/})
    	done <<< "$($words[1] --list-backends)"
    	_arguments "*:keyring priority:(($choices))"
    }
    likely benign LLM, confidence 0.90 Zsh completion function that runs the current keyring command with --list-backends to list priorities and backends.
    Reasoning

    This is the zsh counterpart: $words[1] is the command being completed, run with --list-backends to build the completion choices. It is the same benign completion pattern, and the flagged variable is the user's own command word.

  3. info critical → info by review dynamic-import keyring/core.py:134:5

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

        module_name, sep, class_name = keyring_name.rpartition('.')
        __import__(module_name)
        module = sys.modules[module_name]
        return getattr(module, class_name)
    likely benign LLM, confidence 0.85 Dynamic import of a keyring backend module from a configured dotted class name.
    Reasoning

    The module name comes from splitting a configured keyring backend name on the last dot, then importing that module before getattr to fetch the class. This is the plugin-loading mechanism for a keyring library. The import target is configuration-driven, not fetched from the network or built from obfuscated data. The critical severity reflects the dynamic import pattern itself, not evidence of malicious intent in this code.

  4. info unicode-homoglyph keyring/testing/backend.py:19:6

    identifier `ξεσκεπάζωτηνψυχοφθόραβδελυγμία` contains homoglyph candidates: κ (03BA)→k, η (03B7)→n, ν (03BD)→v, ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "זהכיףסתםלשמועאיךתנצחקרפדעץטובבגן"
        "ξεσκεπάζωτηνψυχοφθόραβδελυγμία"
        "Съешьжеещёэтихмягкихфранцузскихбулокдавыпейчаю"
  5. info unicode-mixed-script keyring/testing/backend.py:19:6

    identifier `ξεσκεπάζωτηνψυχοφθόραβδελυγμία` mixes scripts: Greek + Latin (in string/comment) (raw pass, confidence 0.40)

        "זהכיףסתםלשמועאיךתנצחקרפדעץטובבגן"
        "ξεσκεπάζωτηνψυχοφθόραβδελυγμία"
        "Съешьжеещёэтихмягкихфранцузскихбулокдавыпейчаю"
  6. info warn → info by review dynamic-attribute keyring/util/platform_.py:39:13

    reach-by-name through `globals.get` (ast pass, confidence 0.60)

    # by default, use Unix convention
    data_root = globals().get('_data_root_' + platform.system(), _data_root_Linux)
    config_root = globals().get('_config_root_' + platform.system(), _config_root_Linux)
    likely benign LLM, confidence 0.90 Selects the platform-specific data root directory by looking up a module-level constant named after the OS.
    Reasoning

    globals().get looks up one of several module-level constants (_data_root_Linux, _data_root_Darwin, etc.) by the OS name from platform.system(), with a Linux default. This is a common, simple way to pick platform-specific paths. It reads only fixed local constants, so it cannot reach arbitrary code.

  7. info warn → info by review dynamic-attribute keyring/util/platform_.py:40:15

    reach-by-name through `globals.get` (ast pass, confidence 0.60)

    data_root = globals().get('_data_root_' + platform.system(), _data_root_Linux)
    config_root = globals().get('_config_root_' + platform.system(), _config_root_Linux)
    likely benign LLM, confidence 0.90 Selects the platform-specific config root directory by looking up a module-level constant named after the OS.
    Reasoning

    Same OS-keyed lookup of platform-specific config root constants, with a Linux fallback. It is a benign platform-dispatch pattern that reads only fixed module constants.

Reproduce This Scan

Run disclude locally to verify. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.0.0
git clone https://github.com/jaraco/keyring keyring && cd keyring
git checkout v25.7.0
disclude scan --severity info --diff v25.6.0 .