| Version | Supported |
|---|---|
| 1.x | ✅ |
| < 1.0 | ❌ |
Do not open a public issue.
Use GitHub's private vulnerability reporting — it is private to the maintainers and creates an advisory automatically.
Please include:
- The affected version and store (
MemoryStore,RedisStore, or a custom one) - A minimal reproduction
- What an attacker gains, and what access they need to get it
You can expect acknowledgment within 48 hours, regular updates, and credit in the advisory unless you would rather stay anonymous.
NexoCache is a library, so its threat model is narrower than an application's. These are the things that would be treated as security bugs:
| Issue | Why it matters |
|---|---|
| A cache key collision that lets one caller read another's entry | The worst failure a cache can have |
RedisStore.clear() or invalidateTag() touching keys outside its prefix |
Deleting data the library does not own |
| A crafted key escaping its namespace via separator or glob injection | Same, by a different route |
| A corrupt or forged stored value being returned instead of a miss | Breaks the fail-secure contract |
encryptionPlugin producing predictable ciphertext or accepting a forged tag |
Defeats the point of encrypting at rest |
| Secrets or cached values leaking into logs, traces or error messages by default | Cached data is routinely personal |
| Unbounded growth reachable from untrusted input | A denial of service you can trigger remotely |
A wrap() factory being invoked more or fewer times than the contract says |
Stampede protection is a load-shedding control |
- Caching sensitive data without encryption. The cache stores what you give it; use
encryptionPluginif the store is not trusted. - A key you built that omits the user ID. Serving one user another's data is the most damaging cache bug there is, but the key is yours to construct. See Best Practices.
- Redis being reachable without a password. That is your deployment.
ttl: 0retaining data forever. It is an explicit opt-in.
These are deliberate and tested. A change that breaks one is a regression, not a refactor:
clear()never issuesFLUSHDB. It scans its own prefix and unlinks what it finds. An empty prefix is rejected at construction, because without one there is nothing to scope the deletion to.- Glob metacharacters in a prefix are escaped, so
prefix: 'a*b'cannot widen a SCAN pattern into keys it does not own. - A value that fails to deserialize, decrypt or decompress becomes a miss. Returning the raw bytes would turn a security control into a leak.
encryptionPluginuses AES-256-GCM with a fresh IV per write. Authenticated, so tampering fails loudly; randomised, so repetition leaks nothing.- Values and keys are omitted from logs and traces by default. Including them is an explicit decision.
- The memory store is bounded.
maxSizehas a default so an unbounded cache is never the accident.
- No secrets in code, tests or fixtures — not even fake-looking ones.
- Anything touching key construction, prefix scoping or the plugin transform chain needs a test asserting the failure mode, not just the happy path.
npm auditruns in CI. The package has zero runtime dependencies, which is itself the main supply-chain control; adding one is a decision worth arguing for.
Announced through GitHub Security Advisories and the CHANGELOG.md. Patches ship as a
release on the affected major version.