SoulCache v1.1.1
High-performance data fetching and caching runtime for TypeScript. Zero runtime dependencies. Framework-agnostic.
This is a security patch release following an independent security review. All four
packages (@soulcache/core, @soulcache/react, @soulcache/devtools,
@soulcache/devtools-core) are bumped to 1.1.1. The public API is fully compatible
with v1.1.0 / v1.0.0.
Highlights
- Honest checksum algorithms —
checksum: 'sha-256'now writes a real FIPS 180-4
SHA-256 digest (64-hex) instead of silently reusing the non-cryptographic 32-bit
djb2 hash that every label produced before. Deprecated labels that were never
implemented (sha-384,sha-512,md5) are rejected on write; payloads persisted
by earlier versions under any label remain readable. - No
error.stackin dehydrated state by default — internal file paths no longer
leak to clients in SSR flows. Opt back in withincludeStack: truefor
server-side debugging. - Hardened
hydrate()— malformed entries (non-arrayqueryKey, non-object
query) are rejected before they can corrupt the cache. - CSPRNG-generated ids —
generateId()usescrypto.randomUUID()when available.
What's Changed
Security
- Checksum integrity (SLC-INTEGRITY-001).
JsonSerializer/JsonDeserializer
now honor the configuredChecksumAlgorithm:sha-256computes a real, synchronous, zero-dependency SHA-256 digest (FIPS
180-4) — previously the label silently produced the same 32-bit djb2 value as
every other label.- Writes under
sha-384,sha-512, ormd5throwSerializationError(these
labels were never implemented and are deprecated; migrate tosha-256or the
defaultfast-32). - Reads under
sha-256verify against both the real digest and the legacy djb2
value, so 1.0.0/1.1.0 payloads keep validating; legacy labels remain readable.
- Stack disclosure (SLC-HYDRATE-003).
dehydrate()no longer includes
error.stackby default; passincludeStack: trueto preserve it for server-side
debugging. - Hydrate tampering (SLC-HYDRATE-001).
hydrate()structurally validates every
entry before writing; malformed entries are skipped. The defaultoverwrite
merge strategy is unchanged. - Weak ids (SLC-RNG-001).
generateId()preferscrypto.randomUUID(), with the
legacy scheme retained as a fallback.
Documentation
SECURITY.mdadds secure-usage guidance (query-key scoping, trusted hydrate
sources, checksum = corruption detection not tamper-proofing, stack opt-in).- New consumer security page
docs/content/docs/security.mdx. - Release notes and migration guide updated for v1.1.1.
Testing
- New SHA-256 test suite with FIPS 180-4 vectors (empty, "abc", two-block, padding
boundary) plus serializer/deserializer dual-mode, hydration validation, and
CSPRNG id tests. - Root suite green on the release commit; public API verified compatible with the
v1.0.0 baseline.
Breaking Changes
None. No public API signature changed. Two opt-in/opt-out behavior changes to
review (see Upgrade Notes).
Upgrade Notes
- Dehydrated error entries no longer include
error.stackby default. If you used
stacks from dehydrated state (e.g. SSR debugging), pass
dehydrate(engine, { includeStack: true })— and keep stacks server-side. - If you configured
checksum: 'sha-384' | 'sha-512' | 'md5', serialization now
throws. Switch tosha-256(real) or drop the option (defaultfast-32).
Persisted payloads never need migration; they restore correctly.
Known Limitations
- Checksums are unkeyed: both
fast-32andsha-256detect accidental corruption,
not an attacker who can rewrite both payload and checksum. Use authenticated
storage (HMAC/encryption) where adversarial persistence is in scope. - Retry engine and the plugin system remain internal modules.
Credits
Maintained by Kasih Agustinus and the SoulCache contributors.