# Copiadora: bypass de pré-fixo de confiança via via via via via via via via via tarefas de execução sem compromisso Em copiadora `>= 9.5.0, <= 9.15.1 `, a combinação de prefixos da opção `confiança` (`copier/_settings.py`) compara a URL do modelo com um prefixo confiável com um `str. startswith' bruto e ** sem normalização de caminho**, enquanto a URL * é* normalizada quando o modelo é realmente captado (`Path.resolve()` para caminhos locais; remoção de pontos- segmento libcurl para `https`). Uma referência de modelo que, textualmente, começa com um prefixo confiável, mas contém `..` (por exemplo, ` é portanto concedida confiança ainda resolve para um modelo diferente, controlado pelo atacante, cujas `tarefas` / `migrações` / `jinja_ extensions` então executam ** sem o `- trust` prompt** — execução arbitrária de comandos. Provavelmente ** CWE- 22 (Limite de um nome de caminho mais adequado)** na verificação de confiança que leva a ** CWE- 94 (execução de código)**. `confiança` permite aos usuários marcar as localizações do modelo como confiáveis, então copiadora pula o portão de características inseguras. Um '/` que segue faz uma entrada com **prefix** (`docs/settings.md`: *"Os locais que terminam com '/` serão igualados como prefixos, confiando em todos os modelos daquele local"*).
` copiador/_ settings.py: 141 - 146 ` (tag ` v) 9.15.1 `). ````python retorna any( repository.startswith(_normalize(t))) se t. endswith("/") senão o repositório == _normalize(t) for t in trust ) ``` `_normalize` somente expande `~`; ele faz **não** tocar `...` ou colapsar segmentos — `copier/_ settings.py: 149 - 152 ` (tag ` v) 9.15.1 `): ```python def _normalize(url: str) -> str: se url. startwith("~"): # Expanda somente em str para evitar mexer com URLs url = expandeuser(url) # noqa: PTH 111 devolver url ```.
Esta decisão é executada por código de portões — ` copiador/_ main.py: 293 ` (tag ` v) 9.15.1 `): ```python se self. insegure ou is_ truded_repository( self.settings.trust, self. template.url): devolve o # pule a verificação de características inseguras completamente ``` A cadeia: a comparação de confiança vê o URL **raw**, então `" é `Verdade'; mas as mãos de copiador de valor para `git`/`pathlib` é **normalizado**, então o modelo realmente carregado é `evilorg/t` (uma org diferente, de propriedade do atacante). Confiança é concedida a um local em que o usuário nunca confiou, e `_check_unsafe` retorna cedo, de modo que as tarefas do modelo malicioso executam sem nenhum aviso.
Isto é mais agudo no `update de copiador`, que lê `_src_path` a partir do projeto `.copier- answers.yml` (`copier/_subproject.py`) — ou seja, um atacante que lhe entrega um projeto controla a URL a qual a verificação de confiança é aplicada. A assimetria in- reposo confirma a omissão: copiador resolve consistentemente caminhos * em todos os outros lugares* ele toma uma decisão de segurança — `Path.resolve()` mais `is_relative_to(...)` guardas em `_render_ template`, `template_copy_root` e `_external_data` — mas não na comparação de confiança. Script independente contido em si mesmo; executa- se contra uma instalação limpa e afiada do PyPI via a verdadeira `copiadora` CLI somente. ** Estatístico por padrão** (`copia de cópia -- pretend' chega à decisão de confiança, mas não executa tarefas); `-- prove- exec` é uma execução suplementar opt- in que dispara um marcador inerte (` echo` + ` touch`). O `poc.py` completo acompanha este relatório.
``` Bash python - m venv venv & &. venv/bin/activate pip install "copier"== 9.15.1 " python poc.py # estática (predefinida) python poc.py --prova-exec # também dispara o marcador inerte ``` Saída observada (`copiadora') 9.15.1 `). ``` == versão de prova == copiadora == 9.15.1 módulo:.../site-pacotes/copiadora/__init__.py == Inputs == prefixo confiável (settings.yml): /tmp/copier_trust_poc_XXXX/trust_templates/ control src (canônico): /tmp/copier_trust_poc_XXXX/attacker/evil_template exploit src (traversal): /tmp/copier_trust_poc_XXXX/trust_templates/./attacker/evil_template ambos resolvem para o dir SAME: Verdadeira exploração começa com confiável/: Verdadeira delta mínima: exploit = '/tmp/copier_trust_poc_XXXX/trust_templates/.' + '/attacker/evil_template'.
== Prova estática (copia de cópia -- pretenden; carga útil NÃO executada) == controle (canônico, não confiado): saída= 4 -> Explore BLOQUEADO (UnsafeTemplateError) (prefixo confiável /..): saída= 0 -> Confiança, tarefa alcançada no marcador do disco depois do -- fingir: Falso (falso esperado: -- fingir não executa tarefas) --- a própria saída da copiadora para a exploração (note a tarefa que executaria) ---. Copiando da versão do modelo Nenhum. crie hello.txt. > Executando tarefa 1 de 1: eco COPIER- TRUST- BYPASS- RCE- MARKER & & touch COPIER_RCE_PROOF == VERDICT == BYPASS CONFIRMED: o modelo idêntico é recusado pelo caminho canônico (saída) 4 ) ainda assim, a confiança concedida via ' /..' via transversal (saída 0 ), assim suas tarefas executam sem -- confid prompt.
== --prov-exec: executando a exploração para real (marcador inerte) ==. 1 de 1: eco COPIER-TRUST-BYPASS- RCE-MARKER & & touch COPIER_RCE_PROOF saída= 0 o arquivo de marcador 'COPIER_ RCE_ PROOF' criado: Verdadeiro -> COMANDO ARBITRARIO EJECUTO através de um modelo 'confiado', sem --confiança ``` O exploit é o mesmo modelo que o controle mais o delta mínimo ` /..`. Determinístico: mesmo input → mesmo resultado. O PoC usa um prefixo confiável local para uma execução auto- contida e livre de rede; o caso `https` é idêntico porque git normaliza `..` antes do pedido — por exemplo, `git ls- remote ' emite `alerta: redirecionando para e retorna `pallets/flask`'s refs, um org diferente do confiável `copier-org/`. Um usuário que configurou um prefixo **** (um item trailing-`/` em `confiança', uma funcionalidade documentada) não recebe mais o aviso de características inseguras para um modelo que simplesmente * aparece* para viver sob esse prefixo. Qualquer parte que possa influenciar o URL do modelo — mais realistamente o autor de um projeto, a vítima executa a ` atualização do copiador`, uma vez que `_src_path` vem do `.copier- answers.yml` do projeto — pode hospedar o modelo real sob um org/ local diferente alcançado via `..' e ter suas `tarefas`/ `migrações`/ `jinja_ extensions` executar comandos arbitrários sem nenhum aviso. Ele dispara em um git padrão, moderno para ambos os caminhos locais e `https`.
Severidade proposta: **High**, comparável ao aviso prévio de template inseguro do projeto (GHSA- 3 xw 7 - v 6 cj- 5 q 8 H). CVSS proposto v 4 vetor (maintainer para finalizar; ` AT: P` reflete a configuração de prefixo confiável necessária): ` CVSS: 4.0 /AV:L/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/África do Sul:H`. Variante conservadora se você escopou impacto apenas para a conta de usuário (sem reclamação de escape do host): solte `SC/SI/África do Sul` para `N'. Normalize ** ambos os lados** antes de comparar, em vez de "startswith" bruto. Para entradas locais, compare caminhos absolutos resolvidos (`Path(t).resolve()` vs `Path(repository).resolve()`) usando contenção de segmentos / `is_relative_to`, o padrão já usado em `_render_ template` e `template_copy_root`. Para os itens URL, analise o URL e rejeite ou colapse `..`/`.`/ segmentos do caminho vazio antes do teste do prefixo. Como defesa em profundidade, rejeitar qualquer `_src_path` lida a partir de um arquivo de respostas que contenha segmentos `...` após o esquema/host, uma vez que URLs de modelo legítimos nunca precisam deles. - CWE- 22 — 22.html - CWE- 94 — 94.html - Fonte afetada (tag ` v 9.15.1 `): ` copiador/_ settings.py: 141 - 146 ` (comparação de prefixo), ` copiador/_ settings.py: 149 - 152 ` (`_ normalize`), ` copiador/_ main.py: 293 ` (portão de confiança). - Comportamento do prefixo documentado: `docs/ settings.md` ("Locações terminando com `/ ' será igualado como prefixos"). - `https` `..` normalização: libcurl remove segmentos de pontos por padrão (`CURLOPT_PATH_AS_IS` por omissão para desligar) — - Novidade: distinta dos avisos publicados de copiadores, que se referem ao sistema de arquivos ler/ escrever transversal na saída renderizada; este é um bypass de autorização na correspondência do URL da configuração `trust`. A correspondência falha é idêntica entre o ` v 'release' 9.15.1 ` e atual `master` HEAD, e inalterado desde que a funcionalidade de prefixo de confiança foi introduzida em ` v 9.5.0 ` (originalmente ` copiador/ settings.py`, commit ` 71358 ed`; renomeado para ` copiador/_ settings.py` no v 9.12.0 refator).
Registro de aconselhamento: GHSA- 9 gmc- jqmh- 3 Rvm. Identificadores relacionados: CVE- 2026 - 53951. Tempo: GitHub Advisory Database publicou este registro em 2026 - 08 - 19 T 19: 16: 54.000 Z e lista a sua última modificação como 2026 - 08 - 19 T 19: 16: 54.000 Z. Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 4: CVSS: 4.0 /AV:L/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/África do Sul:H.
Informações sobre software e versão afetadas: copiadora de pacotes PyPI — ECOSYSTEM: introduzido 9.5.0, corrigido 9.15.2. Classificação e evidência: identificadores de fraqueza CWE- 22, CWE- 94. O registro contém 4 suporte de referências nestes tipos: WEB, AVISO, EMBALAGAMENTO.