Descrição Quando um hospedeiro empurra um objeto CLR para um Scriban TemplateContext via o padrão padrão documentado — var assim = novo ScriptObject(); então["user"] = atualUser; // contexto de referência CRL direto.PushGlobal( so); — TypedObjectAccessor expõe todas as propriedades do poder público para tanto para leitura quanto escrita , e escreve terra no objeto hospedeiro vivo e persistir depois de Render() retorna . O caminho de gravação não executa CanWrite e nenhuma verificação de visibilidade do setter, produzindo duas fraquezas relacionadas, mas distintas: (A) Atribuição em massa de setters públicos — CWE- 915 (originalmente F- 002. Qualquer propriedade { get; set; } é escrevible a partir do código do modelo ( {{ user.is_admin = true }} , {{ order.total_price = 0 }} ). Isto é "surpreendente, mas tecnicamente consistente com o setter ser público" — e, crucialmente, Scriban oferece não há maneira de expor tal propriedade somente leitura , porque MemberFilter é lido/escrito-simétrico. (B) O bypass de modificador de acesso — CWE- 284 (originalmente F- 007. Propriedades do desenvolvedor deliberadamente restritas também são redigibles, porque a reflexão ignora a acessibilidade do C#:.
Declaração Objectivo do desenvolvedor Comportamento atual --. --. -- { get; set; }. writable. writable (assignação de massa — A) { get; private set; }. somente a classe proprietária escreve o modelo escreve livremente { get; internaset; }. apenas a assembléia declarante escreve o modelo escreve livremente { get; init; }. imutável após a construção (C# 9 garantia de idioma). template escreve livremente após a construção.
O 'code>init -somente pós-construção gravação — o maior risco falso-positivo — foi explicitamente confirmado contra o enviado 7.2.1 pacote. Versões afetadas Todos os lançamentos que a nave Accessor ObjetoTipado ( &#x 3 C;= 7.2.1 ). MembrosPrepares tem usado o filtro getter- somente desde que o acessório foi introduzido, e TrySetValue nunca avaliou o setter. O bypass init aplica-se no.NET 5 +; set privado / set interno aplica- se em cada tempo de execução suportado. Não existe nenhuma versão correcionada. Pasos para Reprodução Copiar- pega. Execute a partir da raiz de engajamento (a pasta contendo ambos os scriban/ e relatórios/ ). Prereqs: teste -d scriban ї { eco "fonte de script faltante"; saia 1; } ( comando - v dotnet >/ dev/null &#x 26;&#x 26; dotnet -- lista- sdks Ì grep -q '^ 10 \.' ) \.. ( "$HOME/. dotnet/ dotnet" --list-sdks. grep -q '^ 10 \.' ) \ ї (') { eco ".NET 10 Faltando SDK"; saída 1; } exportar PATH="$HOME/.dotnet:$PATH" Execute ambos os PoCs (nativo): ( cd reports/f 002 /poc &#x 26;&#x 26; dotnet run - c Release ) # (A) atribuição de massa ( cd reports/f 007 /poc &#x 26;&#x 26; dotnet run - c Release ) # (B) privado/interno/init bypass Docker repliback (não é necessário SDK nativo): docker run --rm -v "$PWD":/work -w /work/reports/f 007 /poc \ mcr.microsoft.com/ dotnet/ sdk: 10.0 Bash -lc "dotnet run -c Release" Confirme que o pacote publicado é afetado (não apenas mestre): trocar o ProjectReference em relatórios/f 007 /poc/poc.csproj para &#x 3 C;PackageReference Include="Scriban" Versão=" 7.2.1 " /> e re-execução — os quatro bypass ainda têm sucesso. Cada PoC imprime [ 1 ] Valores CLR originais, [ 2 ] saída do modelo (li original → escreve → lê de volta), e [ 3 ] o C#-side lido após Render() provando que o objeto hospedeiro ao vivo foi permanentemente alterado. Remediação Os fixos estão listados plano. Note que (B) tem uma correção de código limpa e claramente correta; (A) requer um controle novo porque as gravações do public-setter são de outra forma por- desenho. Fix 1 — bloqueio de configuradores restritos em TrySetValue ( Tipo deAcessor.cs L 108 – L 123 ). Correções (B). Antes do L 120 SetValue , requer um conjunto público, não init setter: var setM = propriedadeAccessor.GetSetMethod(nonPublic: false); se (setM é nulo) devolver falso; // privado / interno / protegido setters se (setM.ReturnParameter.GetRequiredCustomModifiers().Any(m => m.FullName == "System.Runtime.CompilerServices.IsExternalInit")) devolve falso; // init- unicamente: setter IS public, por isso a verificação IsExternalInit é REQUISTA Um simples código não é suficiente para 2 — dar aos hosts uma distinção de leitura/escreva (endereços (A)). Adicione um MembroScritaFiltro em TemplateContext (separado de MembroFiltro ) e/ou um atributo [ScriptMemberReadSolo] , e divida _membros em _legívelMembros / _writableMembros em Membros Preparados (L 126 – L 186 ). A atribuição de massa da tabela pública não pode ser bloqueada sem um destes, porque MemberFilter é lida/símétrica hoje. Fix 3 — restaurar a leitura-somente-por-default no ScriptObject.Importar ( ScriptObjectExtensions.cs L 320 – L 324. Porte o relaxamento da compatibilidade com líquido por trás de um opt-in explícito em vez de remover proteção de gravação globalmente. Fix 4 — documentação ( site/docs/runtime/safe-runtime.md ). Estabeleça explicitamente que os modelos podem escrever propriedades CLR através da reflexão (incluindo privado / interno / init ), e que MembroFiltro não separa a leitura da escrita. Fix 5 — testes de regressão ( src/Scriban.Tests/ ). Asserte set privado / set interno / init não são gravables a partir de modelos, que MembroWriteFilter / [ScriptMemberReadSolo] porte escreve, e que somente o público set é escrevible. 2 Data-heading="Referências">Referências Caminho de gravação variável (sem verificação do setter): criban/src/Scriban/Runtime/Accessores/Accessor Objeto Tipo.cs L 108 – L 123 ( TrySetValue ), afundar em L 120 propriedadeAcessor.SetValue(target, context.ToObject(span, value, propertyAccessor.PropertyType)); Filtro de membro mais importante: TipedObjectAccessor.cs L 126 – L 186 ( Membros Preparados ), enumeração em L 150, portão em L 156; mesmo _members consumido por TryGetValue (L 66 – L 83 ) Envio de atribuições de membros: criban/ src/ Scriban/ ScribanAsync.generated.cs: 2297 ( acessório.TrySetValue((...) ) e o avaliador síncrono Sem separação de leitura/escreva: MembroFiltro declarado TemplateContext.cs: 286 , aplicado TemplateContext.cs: 1026 ; ScriptObject.Importar remoção de apenas leitura ScriptObjectExtensions.cs: 320 – 324 .NET reflexion bypass access modifiers: init accessores (C# 9 ): 9.0 / init CWE- 915 — 915.html CWE- 284 — 284.html.
Registro de aconselhamento: GHSA- 7 jvp-hj 45 - 2 f 2 m. Não há nenhum identificador adicional listado.
Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 06 T 17: 30: 17.000 Z e lista a sua última modificação como 2026 - 07 - 06 T 17: 30: 17.000 Z.
Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 4: CVSS: 4.0 /AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/África do Sul:N/E:P.
Software afetado e informações de versão: Pacote NuGet Scriban — ECOSYSTEM: introduzido 0, corrigido 7.2.2.
Classificação e evidência: identificadores de fraqueza CWE- 284, CWE- 915. O registro contém 2 suporte de referências nestes tipos: WEB, PACKAGE.