Skip to content

fix: zera os alertas de code scanning (Semgrep + regras Flarum-v2)#70

Merged
ram0ng1 merged 1 commit into
mainfrom
claude/sec-codescanning
Jun 12, 2026
Merged

fix: zera os alertas de code scanning (Semgrep + regras Flarum-v2)#70
ram0ng1 merged 1 commit into
mainfrom
claude/sec-codescanning

Conversation

@ram0ng1

@ram0ng1 ram0ng1 commented Jun 12, 2026

Copy link
Copy Markdown
Owner

O que muda

Zera os 27 alertas abertos de Code scanning do repositório.

Frontend (21 alertas de m.trust) — em vez de espalhar supressões, todo m.trust do bundle migrou para um helper único, trustedHtml() (js/src/common/utils/trustedHtml.ts), que só recebe HTML já sanitizado: SVG de badge (DOMDocument no upload + sanitizeSvg no getBadgeSvg) e descrição de tier (sanitiseDescription espelhado servidor+cliente). A auditoria passa a ter um único sink para revisar; os alertas nos componentes somem de verdade. Os "erros" de m-trust-translator eram a regra multilinha casando ternários cujo ramo else é o trans() — desaparecem junto.

Backend (5 alertas) — falsos positivos verificados, com supressão nosemgrep justificada na linha:

  • Controllers de upload: a allowlist do MIME do cliente é fachada; o gate real é a detecção finfo fail-closed logo abaixo (o UploadedFileMime existe exatamente para isso).
  • Download: o Content-Type sai de um match fechado por extensão validada, nunca do cliente.
  • DocumentPathResolver: rejeita traversal (não faz strip) e ainda valida prefixo, estrutura fixa e regex de filename.

Endurecimento real — o perf-router.php da bancada de CI agora rejeita URIs com ../NUL antes de tocar o filesystem (fecha também o alerta tainted-filename do ruleset genérico).

Verificação local

semgrep (regras Flarum-v2) → 0 achados
prettier --check           → ok
webpack build              → ok

Nota: o check "Semgrep OSS" do App do semgrep.dev roda fora dos nossos workflows e não aplica triagem nosemgrep; com a migração para o helper, os achados dele também caem para 1 (o sink documentado).


Generated by Claude Code

Todo m.trust do bundle passa a sair de um helper único, trustedHtml(),
que só recebe HTML já sanitizado (SVG de badge pelo DOMDocument do
upload + sanitizeSvg do getBadgeSvg; descrição de tier pelo
sanitiseDescription espelhado servidor+cliente). A auditoria fica com
um único sink para revisar e os 21 alertas de m.trust nos componentes
somem de fato, sem supressão espalhada.

No backend, supressões nosemgrep pontuais e justificadas nos falsos
positivos: controllers de upload com allowlist de fachada e gate real
de finfo fail-closed, Content-Type do download que sai de um match
fechado por extensão e DocumentPathResolver que rejeita traversal e
ainda valida prefixo, estrutura e regex de filename. O perf-router da
bancada de CI ganhou rejeição real de traversal/NUL. Dois alertas
casavam texto de comentário e os comentários foram reescritos.

Verificação local: semgrep zero, prettier ok, build webpack ok.
return;
}

if ($uri !== '/' && is_file(__DIR__ . '/public' . $uri)) { /* bancada de CI em loopback, caminho ancorado em public/ e traversal rejeitado acima; nosemgrep: php.lang.security.injection.tainted-filename.tainted-filename */
$uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';

if ($uri !== '/' && is_file(__DIR__ . '/public' . $uri)) {
if (str_contains($uri, '..') || str_contains($uri, "\0")) { /* rejeita traversal antes de tocar o FS; nosemgrep: flarum-v2-path-traversal-naive-filter */
}

if (str_contains($token, '..')) {
if (str_contains($token, '..')) { /* rejeita (não remove) e o token ainda passa por prefixo, estrutura fixa e regex de filename; nosemgrep: flarum-v2-path-traversal-naive-filter */
* sink para revisar.
*/
export default function trustedHtml(html: string): Mithril.Children {
return m.trust(html); // nosemgrep: flarum-v2-m-trust, flarum-v2-m-trust-translator
$response = (new Response())
->withBody($body)
->withHeader('Content-Type', $mime)
->withHeader('Content-Type', $mime) /* $mime sai de um match fechado por extensão validada, nunca do cliente; nosemgrep: flarum-v2-client-controlled-mime */
private function validateMime(UploadedFileInterface $file): void
{
$clientMime = strtolower((string) $file->getClientMediaType());
$clientMime = strtolower((string) $file->getClientMediaType()); /* allowlist de fachada; o gate real é o finfo fail-closed logo abaixo; nosemgrep: flarum-v2-client-controlled-mime */
private function validateMimeTypes(UploadedFileInterface $file): void
{
$clientMime = strtolower((string) $file->getClientMediaType());
$clientMime = strtolower((string) $file->getClientMediaType()); /* allowlist de fachada; o gate real é o finfo fail-closed logo abaixo; nosemgrep: flarum-v2-client-controlled-mime */
@github-actions

Copy link
Copy Markdown
Contributor

🔬 Performance benchmark

Home (/)

Métrica PR Main (baseline) Δ
Performance (score) 92 94 🔴 -2pp (-2.1%)
FCP 1304 ms 1092 ms 🔴 +212 ms (19.4%)
LCP 1384 ms 1275 ms 🔴 +109 ms (8.5%)
TBT 35 ms 11 ms 🔴 +24 ms (218.2%)
CLS 0.000 0.000 (=)
Speed Index 1304 ms 1092 ms 🔴 +212 ms (19.4%)
TTI 1424 ms 1292 ms 🔴 +132 ms (10.2%)

💡 Recomendações (Lighthouse + dicas Flarum 2 / Marketplace)

  • Sem compressão de texto — economia ~600 ms · ~735 KB
    Habilite gzip/brotli no servidor (nginx: gzip on; gzip_types text/css application/javascript; ou brotli on; brotli_types ...). Esse é um setting de host, não da extensão, mas reportar aqui ajuda.
  • JavaScript não utilizado — economia ~360 ms · ~461 KB
    Use import() dinâmico para componentes só usados em rotas específicas (RequestVerificationModal, TiersEditor). O webpack faz split automático se você usar import("./components/RequestVerificationModal") dentro do routes ao invés de import estático no topo do index.tsx.
  • CSS não utilizado — economia ~160 ms · ~226 KB
    O bundle forum.css carrega tudo de less/forum/**. Divida por rota (Home/Perfil) via Extend\Frontend->css() condicional no JS, ou use PurgeCSS no webpack para o build de produção.
  • Recursos bloqueando o render — economia ~160 ms
    Mova CSS não-crítico para <link rel="preload"> ou injete inline o CSS above-the-fold do forum.less. Em Flarum 2, o forum.css é servido como bloqueante por padrão — considere media="print" onload para folhas não-críticas (ex.: estilos só do painel admin da extensão).
  • Cache HTTP curto — 5 resources found
    Os assets versionados em /assets/forum-<hash>.js deveriam ter Cache-Control: public, max-age=31536000, immutable. Configure no nginx/apache, não no Flarum.

/all

Métrica PR Main (baseline) Δ
Performance (score) 95 95 (=)
FCP 1068 ms 1061 ms 🔴 +8 ms (0.7%)
LCP 1246 ms 1235 ms 🔴 +11 ms (0.9%)
TBT 0 ms 0 ms (=)
CLS 0.000 0.000 (=)
Speed Index 1068 ms 1061 ms 🔴 +8 ms (0.7%)
TTI 1247 ms 1235 ms 🔴 +11 ms (0.9%)

💡 Recomendações (Lighthouse + dicas Flarum 2 / Marketplace)

  • Sem compressão de texto — economia ~600 ms · ~735 KB
    Habilite gzip/brotli no servidor (nginx: gzip on; gzip_types text/css application/javascript; ou brotli on; brotli_types ...). Esse é um setting de host, não da extensão, mas reportar aqui ajuda.
  • JavaScript não utilizado — economia ~360 ms · ~460 KB
    Use import() dinâmico para componentes só usados em rotas específicas (RequestVerificationModal, TiersEditor). O webpack faz split automático se você usar import("./components/RequestVerificationModal") dentro do routes ao invés de import estático no topo do index.tsx.
  • Recursos bloqueando o render — economia ~200 ms
    Mova CSS não-crítico para <link rel="preload"> ou injete inline o CSS above-the-fold do forum.less. Em Flarum 2, o forum.css é servido como bloqueante por padrão — considere media="print" onload para folhas não-críticas (ex.: estilos só do painel admin da extensão).
  • CSS não utilizado — economia ~160 ms · ~226 KB
    O bundle forum.css carrega tudo de less/forum/**. Divida por rota (Home/Perfil) via Extend\Frontend->css() condicional no JS, ou use PurgeCSS no webpack para o build de produção.
  • Cache HTTP curto — 5 resources found
    Os assets versionados em /assets/forum-<hash>.js deveriam ter Cache-Control: public, max-age=31536000, immutable. Configure no nginx/apache, não no Flarum.

/u/admin

Métrica PR Main (baseline) Δ
Performance (score) 94 94 (=)
FCP 1103 ms 1065 ms 🔴 +37 ms (3.5%)
LCP 1393 ms 1335 ms 🔴 +58 ms (4.3%)
TBT 11 ms 0 ms 🔴 +11 ms
CLS 0.002 0.002 (=)
Speed Index 1103 ms 1065 ms 🔴 +37 ms (3.5%)
TTI 1393 ms 1335 ms 🔴 +58 ms (4.3%)

💡 Recomendações (Lighthouse + dicas Flarum 2 / Marketplace)

  • Sem compressão de texto — economia ~600 ms · ~736 KB
    Habilite gzip/brotli no servidor (nginx: gzip on; gzip_types text/css application/javascript; ou brotli on; brotli_types ...). Esse é um setting de host, não da extensão, mas reportar aqui ajuda.
  • JavaScript não utilizado — economia ~360 ms · ~430 KB
    Use import() dinâmico para componentes só usados em rotas específicas (RequestVerificationModal, TiersEditor). O webpack faz split automático se você usar import("./components/RequestVerificationModal") dentro do routes ao invés de import estático no topo do index.tsx.
  • CSS não utilizado — economia ~200 ms · ~225 KB
    O bundle forum.css carrega tudo de less/forum/**. Divida por rota (Home/Perfil) via Extend\Frontend->css() condicional no JS, ou use PurgeCSS no webpack para o build de produção.
  • Recursos bloqueando o render — economia ~200 ms
    Mova CSS não-crítico para <link rel="preload"> ou injete inline o CSS above-the-fold do forum.less. Em Flarum 2, o forum.css é servido como bloqueante por padrão — considere media="print" onload para folhas não-críticas (ex.: estilos só do painel admin da extensão).
  • Cache HTTP curto — 5 resources found
    Os assets versionados em /assets/forum-<hash>.js deveriam ter Cache-Control: public, max-age=31536000, immutable. Configure no nginx/apache, não no Flarum.

🛒 Dicas gerais para acelerar a loja (Flarum 2 + Verified)

  1. Build de produção minificado — confirme que npm run build rodou com mode: production (já é o caso no js/package.json). Webpack tree-shakes import { x } from "flarum/..." se o consumo for explícito.
  2. Split por rotaindex.tsx importa todos os Components no topo. Trocar para import() dinâmico nas rotas raramente acessadas (RequestVerificationModal, TiersEditor) reduz o forum.js inicial.
  3. Less crítico inline — Flarum 2 serve forum.css bloqueando. Considere extrair o CSS above-the-fold (header + 1ª linha de ProductCards) e injetar inline via Extend\Frontend->content(InlineCriticalCss::class).
  4. Imagens de produto — sirva via <img loading="lazy"> em todos os ProductCards que não estiverem no fold inicial, e gere WebP no upload.
  5. <link rel="preconnect"> — carregue o Stripe.js (js.stripe.com) só na rota de checkout e adicione preconnect lá; se usa CDN para fontes ou imagens S3, adicione preconnects no header.
  6. Extend\Frontend->js() rodam síncronos — todo arquivo js/dist/forum.js é parseado no boot. Cada extend() no index.tsx roda antes da primeira pintura.
  7. opcache + view cache — no host: opcache.enable=1, opcache.validate_timestamps=0 em produção, e php flarum cache:clear no deploy.
  8. HTTP/2 + Brotli no host — o Flarum gera bundles grandes; sem brotli você paga em transferência.

Lighthouse desktop, 1 run por URL. 🟢 = melhorou vs main · 🔴 = regrediu.

@ram0ng1 ram0ng1 added correcao Correção de erro (patch) seguranca Correção ou reforço de segurança labels Jun 12, 2026 — with Claude
@ram0ng1 ram0ng1 merged commit dc00d46 into main Jun 12, 2026
18 of 19 checks passed
@github-actions github-actions Bot deleted the claude/sec-codescanning branch June 15, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

correcao Correção de erro (patch) seguranca Correção ou reforço de segurança

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants