`pickle.Unpickler`: add hook to intercept `REDUCE` calls
@serhiy-storchaka já está trabalhando nisso.
Desde 9/7/2026.
- Linguagem predominante
- Python
- Estrelas
- 77.2k
- Forks
- 36k
- Métricas de merge de PRs
- Métricas de PR pendentes
Descrição
Feature or enhancement
Proposal:
I want to pickle and unpickle data that may validly contain types.FunctionType instances, but I want to prevent them from being used in REDUCE opcodes, to protect me from RCEs like REDUCE os.system('firefox https://www.youtube.com/watch?v=dQw4w9WgXcQ').
The traditional conservative approach is to use an allowlist, e.g.:
class SafeUnpickler(pickle.Unpickler):
def find_class(self, module, name):
obj = super().find_class(module, name)
if not known_to_be_safe(obj):
raise pickle.UnpicklingError(f"unsupported symbol '{module}.{name}'")
return obj
However, find_class is applied when a GLOBAL/STACK_GLOBAL opcode is executed, before the interpreter knows whether the symbol will be used as a value or passed to REDUCE. I want to permit pickling of any function, including os.system; I just don't want to allow passing it to REDUCE.
So, what I really want is some sort of hook called at REDUCE time. One concrete proposal:
Ts = TypeVarTuple('Ts')
R = TypeVar('R')
def reconstruct(self, constructor: Callable[[*Ts], R], args: tuple[*Ts]) -> R:
# default impl; overrides may raise UnpicklingError
return constructor(*args)
The safe idiom would be:
known_safe_classes = (SomeClass, OtherClass)
def reconstruct(self, constructor: Callable[[*Ts], R], args: tuple[*Ts]) -> R:
if not isinstance(constructor, type):
# prevent e.g. os.system RCE
raise UnpicklingError(...)
if not issubclass(constructor, known_safe_classes):
# prevent e.g. subprocess.Popen RCE
raise UnpicklingError(...)
return constructor(*args)
Dismissed alternatives:
- I can solve my problem by prohibiting functions in
find_class, and instead providing a custom serialization forFunctionTypethroughpersistent_id/persistent_load, but this is unfortunate since I need to re-implement serialization from scratch of a type that is already supported natively. - I can solve my problem by subclassing the undocumented pure-python
pickle._Unpicklerinstead ofpickle.Unpickler, and overriding the undocumentedload_reduce(which cPickle's Unpickler does not honor). This is undocumented and slow.
Has this already been discussed elsewhere?
No response given
Links to previous discussion of this feature:
No response
Guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Avaliação
Esta issue ainda não foi avaliada.