# Relatório de Segurança 04 — XSS armazenado em "Fale Conosco" do órgão

- Data: 2026-06-10
- Severidade: Média/Alta (XSS armazenado em página pública)
- Status: Concluído

## 1. Risco

O campo `faleConoscoExtraInfo` (texto rico, editado no admin de Secretarias/Estruturas) era renderizado sem escape e com decodificação de entidades na página pública do órgão:

```blade
{!! html_entity_decode($secretaria->faleConoscoExtraInfo) !!}
```

A validação na gravação apenas verificava se `strip_tags` ficava vazio; não removia tags/atributos perigosos. Combinado com `html_entity_decode` + `{!! !!}`, permitia **XSS armazenado** (ex.: `<script>`, `onerror=`, `href="javascript:..."`), executado para todos os visitantes da página.

## 2. Correção aplicada

### 2.1 Novo sanitizador reutilizável

`app/Helpers/HtmlSanitizer.php` — método estático `sanitize(?string $html): string`:

- decodifica entidades (evita bypass por payload codificado);
- remove tags perigosas com conteúdo: `script`, `style`, `iframe`, `object`, `embed`, `form`, `applet`, `meta`, `link`, `base`, `svg`, `math`, `frame`, `frameset`, `noscript`;
- remove atributos de evento inline (`on*`);
- neutraliza URIs perigosas em `href`/`src` (`javascript:`, `vbscript:`, `data:` exceto `data:image/`);
- preserva formatação comum (parágrafos, listas, links com `href` seguro, imagens inline).

### 2.2 Sanitização na gravação (entrada)

`app/Http/Resources/SecretariaResource.php` — `normalizedFaleConoscoExtraInfo()` agora passa o conteúdo por `HtmlSanitizer::sanitize()` antes de persistir.

### 2.3 Sanitização na renderização (defesa para dados já existentes)

`resources/views/paginas/parts/org-fale-conosco-miolo.blade.php`:

```blade
{!! \App\Helpers\HtmlSanitizer::sanitize($secretaria->faleConoscoExtraInfo) !!}
```

Cobre também registros gravados antes desta correção, sem necessidade de migração de dados.

## 3. Testes (vetores)

| Entrada | Saída |
|--------|-------|
| `<p class="a">Olá</p><script>alert(1)</script>` | `<p class="a">Olá</p>` |
| `<a href="javascript:alert(1)" onclick="x()">link</a>` | `<a href="#">link</a>` |
| `&lt;script&gt;alert(2)&lt;/script&gt;<b>ok</b>` | `<b>ok</b>` |
| `<img src="data:image/png;base64,xxx"><iframe src="http://x"></iframe>` | `<img src="data:image/png;base64,xxx">` |

- `php -l` sem erros nos arquivos alterados.

## 4. Observações e acompanhamento

- O sanitizador por regex mitiga os vetores comuns, mas não substitui uma whitelist completa (ex.: HTMLPurifier). Caso se deseje rigor máximo, avaliar a adoção de `mews/purifier` numa próxima fase.
- O helper `HtmlSanitizer` deve ser reaproveitado em outros campos renderizados com `{!! !!}` a partir de entrada do usuário (ver Relatório 06 / acompanhamento).
- Recomenda-se também aplicar uma Content-Security-Policy no portal público como camada adicional.

## 5. Arquivos alterados

- `app/Helpers/HtmlSanitizer.php` (novo)
- `app/Http/Resources/SecretariaResource.php`
- `resources/views/paginas/parts/org-fale-conosco-miolo.blade.php`
