Skip to content

security: authenticate cache values with HMAC-SHA256 before unpickling - #147

Merged
D3f0 merged 1 commit into
mainfrom
security/cache-hmac-authentication
Oct 27, 2026
Merged

D3f0 merged 1 commit into
mainfrom
security/cache-hmac-authentication

Conversation

@D3f0

@D3f0 D3f0 commented Oct 27, 2026

Copy link
Copy Markdown
Owner

Summary

Mitigates DiskCache's unpatched GHSA-w8v5-vhqr-4h9v in toolkit cache readers by wrapping raw diskcache.Cache in an AuthenticatedCache that signs every stored value with a private, machine-local HMAC-SHA256 key and verifies it before deserializing.

Also fixes a shell-injection vector in create.script_env where PEP 723 dependency metadata was interpolated into a shell command without quoting.

Changes

src/invoke_toolkit/tasks/cache.py

  • Import AuthenticatedCache and load_cache_key from _cache_security at module level.
  • get_cache() loads the signing key from platformdirs.user_data_dir/cache-signing/cache.key (owner-only permissions required) and returns an AuthenticatedCache, or None if the key store is missing or has unsafe permissions — disabling caching rather than reading unsigned data.

src/invoke_toolkit/tasks/autocomplete.py

  • Delegates cache construction to get_cache() instead of calling diskcache.Cache directly, so completion caches inherit the same authentication.

src/invoke_toolkit/extensions/tasks/create.py

  • Uses shlex.quote when interpolating PEP 723 dependency metadata into the uv invocation, preventing crafted dependency strings from injecting shell commands.

tests/tasks/test_cache_security.py (new)

Comprehensive test suite covering:

  • Unsigned pickles never execute (parametrized over task/async-task/completion/key-iteration readers × inline/file storage)
  • Tampered authenticated values are recomputed, not executed
  • Authenticated values cannot move between keys or caches (replay attack)
  • Insecure signing-state permissions disable caching
  • Symlinked signing keys are rejected
  • Poisoned authenticated payloads (correct HMAC, wrong payload) are rejected
  • Forged Settings entries cannot replace the signing key
  • Foreign filename column entries cannot delete user files
  • Concurrent key publication accepts a complete key

tests/extensions/test_create.py

  • New test_script_env_quotes_dependency_metadata: verifies that a malicious ;-suffixed dependency string is passed verbatim to the installer and not executed by the shell.

pyproject.toml / uv.lock

  • Add anyio>=4.14.2 runtime floor (TLS fixes).
  • Add uv constraint-dependencies for black, filelock, urllib3, uv, and virtualenv (patched releases).

README.md / CHANGELOG.md

  • Document the HMAC authentication scheme and updated dependency floors.

Mitigates DiskCache's unpatched GHSA-w8v5-vhqr-4h9v in toolkit cache
readers by wrapping the raw diskcache.Cache in an AuthenticatedCache
that signs every stored value with a private, machine-local key and
verifies it before deserializing.

Changes:
- cache.py: import AuthenticatedCache and load_cache_key at module level;
  get_cache() now loads the signing key from
  platformdirs.user_data_dir/cache-signing and returns an
  AuthenticatedCache, or None if the key store is unsafe.
- autocomplete.py: delegate cache creation to get_cache() instead of
  constructing diskcache.Cache directly; suppress now-unused diskcache
  import warning.
- create.py: use shlex quoting when passing PEP 723 dependency metadata
  to the package installer so crafted dependency strings cannot inject
  shell commands.
- tests/tasks/test_cache_security.py: new test suite covering unsigned
  pickles, tampered authenticated values, cross-key/cross-cache replay,
  insecure key storage, symlinked keys, poisoned payloads, forged
  Settings entries, file-backed entries, and concurrent key publication.
- tests/extensions/test_create.py: add test asserting that dependency
  metadata is passed verbatim (not executed) to the installer.
- pyproject.toml: add anyio>=4.14.2 runtime floor and uv constraint-
  dependencies for black, filelock, urllib3, uv and virtualenv.
- README.md, CHANGELOG.md: document the cache authentication scheme
  and updated dependency floors.
@D3f0
D3f0 merged commit ddf2867 into main Oct 27, 2026
3 of 4 checks passed
@D3f0
D3f0 deleted the security/cache-hmac-authentication branch October 27, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant