Adding optional signing of cache data

I’m curious to gather opinions on the merits of signing cached data to mitigate the possibility of remote code execution attacks in the event of a cache compromise.

All of Django’s built-in cache backends (in-memory, memcached, Redis, database, and file-based) serialize cache data using pickle. In the event an attacker can write to a cache, the attacker could provide malicious cache data that would execute arbitrary code when unpickled by the Django application server.

This longstanding known issue has been reported on Trac (2024) and HackerOne (2021) and I’ve answered both by saying, “Of course there are going to be problems when servers are compromised. Django could sign the data it puts into the cache, but this probably has too many performance penalties for a cache.”

The Django docs warn:

An attacker who gains access to the cache file can not only falsify HTML content, which your site will trust, but also remotely execute arbitrary code, as the data is serialized using pickle.

(This warning for the file-based cache backend is applicable to all backends.)

With that as background…

I’m part of the team developing a MongoDB backend for Django. It has its own cache backend (since Django’s built-in database cache backend is SQL-specific), and the MongoDB security team has flagged the use of pickle as a vulnerability needing remediation, proposing optional (enabled by default) HMAC signing of cache entries. I’ve pushed back, citing inconsistency with Django’s built-in cache backends and questioning whether the overhead of signing cached data will make the cache perform so poorly as to make it largely useless.

Regardless of the decision that MongoDB makes on this, do you see any merit to adding optional cache signing to Django’s built-in cache backends?

I feel the decision at MongoDB is largely based on liability concerns related to their hosted database offering (e.g. a breach of their Cloud database could lead to comprise of customer application servers), but it also leaves me with a strange impression that perhaps MongoDB is unusually vulnerable to compromise, such that additional protections are necessary. How do you feel about it?

Hey Tim.

I’ve certainly been in situations where we’ve had to switch out the cache serialiser, for e.g. a JSON version, due to the concern here.

Yes, that was my first thought. If pickle is an issue, I’d rather not use it than have a slow cache.

Of course, that limits what can be cached quite significantly.

So maybe one could configure a slow_pickle_cache alias for caching querysets (or whatever), and use signing there. But to be honest, it just feels backwards. (Would I do this? Probably not. And back to swapping the serialiser.)

Perhaps that’s not so helpful, but it’s the mental cycle I’ve been through several times thinking about this. :person_shrugging:

It was an intentional design decision of django-tasks to use JSON to avoid these kinds of RCE vulnerabilities. There are reasons to prevent tampering of cached data other than RCE (namely data integrity), but if an attacker has got to your cache server you’re probably fairly hosed anyway.

Perhaps the best API would be to make the serializer pluggable? That way it’s easy for a user to force JSON without needing to subclass a cache backend, but also providing a signed pickle serializer to mitigate these issues.

I agree on this one. I was trying to write a comment for this idea but couldn’t get a good example setup.

This is really valuable, DRF does this really well for authentication, permissions, etc.

Managed to find this thread after discovering CVE-2025-69872 against diskcache in one of our projects. There are other issues against diskcache that are debated in GitHub issue 357, if it’s a documentation issue, or if it’s an unsafe default.

Looking at Django’s history - the default session serializer was switched to JSON back in Django 1.6, and PickleSerializer was removed in Django 5.0. Again - the other issue for this one was the cookie session backend, as any request sends a cookie session that needed deserializing, and a leaked SECRET_KEY would make remote code execution trivial.

I’d guess that if someone was creating Django from scratch in 2026, using pickle in any form would probably be considered an insecure default to avoid at all costs - even for a cache backend.

The dream for me would be to see a secure default used to reduce the risk to zero, even if it’s slightly painful - a backend that uses JSON/msgpack or another safe serialization format. I’ve just tried this on a Wagtail project (as django-redis supports different serializers) and it was a pretty quick fail, Wagtail’s image thumbnail renditions are stored in cache, and then Django’s page cache middleware relies on caching a TemplateResponse. If page caching is the only internal place that Django relies on cache being able to pickle, then that might be worth the effort in adjusting it to make it more secure by default.

Then as additional options, provide a signed pickle serializer to allow users to continue with a serializer that’s sufficiently backwards compatible, and maybe a less secure serializer if performance is needed. Make it easy for projects to continue with pickle, but make it clear that it’s not as secure.

It’s quite fiddly as Django has a great cache API, but all of the backends are doing their own thing for serialization. Redis backend is storing integers as-is, and everything else is pickled. The memcached backends (pylibmc/pymemcache) use flags to keep strings/integers as-is, and pickles everything else. Django’s file/database/locmem backends pickles all data.

Anyway, if performance is a concern - it’s probably worth benchmarking to see what the impact would be.