Content-Security-Policy é a diferença entre "alguém conseguiu injetar HTML na minha página" e "alguém conseguiu executar código no navegador dos meus visitantes". A primeira é um bug; a segunda é um incidente.
O problema é que a maioria das políticas na internet se parece com isto:
Content-Security-Policy: default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline'
Com 'unsafe-inline' em script-src, a política deixa de impedir o ataque principal que ela deveria impedir. Um script injetado na página executa normalmente. Sobra proteção contra script de domínio externo — útil, mas é a menor parte.
Por que o unsafe-inline aparece
Ele aparece porque o site tem coisas assim, e tirar dá trabalho:
<div style="margin-top: 24px">
<button onclick="enviar()">
<script>var config = {...}</script>
Atributo style, atributo onclick e script embutido são todos bloqueados por uma política fechada. Quem descobre isso no meio de um deploy adiciona 'unsafe-inline', o site volta a funcionar, e a política vira decoração.
O que fazer com cada caso
1. Atributos style
Bloqueado
<p style="color:#999">
Funciona
<p class="t2">
Classes utilitárias resolvem. É trabalho mecânico e chato — em um site de porte médio dá algumas centenas de ocorrências — mas não é difícil, e um grep encontra todas.
2. Manipuladores inline
Bloqueado
<button onclick="enviar()">
Funciona
elemento.addEventListener(
'click', enviar
);
3. Script embutido com dados do servidor
O caso legítimo mais comum: passar configuração do PHP para o JavaScript. A saída não é liberar script inline — é entregar por atributo de dado e ler no JS:
<div id="app" data-limite="50"></div>
// no JavaScript
var limite = +document.getElementById('app').dataset.limite;
A pegadinha do CSSOM
Um detalhe que confunde: com style-src 'self', o atributo style no HTML é bloqueado, mas o JavaScript continua podendo mexer em estilo:
el.style.setProperty('--x', '0.5'); // funciona
<div style="--x: 0.5"> // bloqueado
A política restringe estilo vindo do documento, não a manipulação via CSSOM. Efeito visual dinâmico feito em JavaScript continua funcionando com a política fechada.
Um degrau acima: Trusted Types
Fechado o unsafe-inline, sobra o XSS baseado em DOM — quando o próprio código do site escreve dado não confiável em um sink perigoso:
caixa.innerHTML = '<p>' + textoDoUsuario + '</p>';
Nenhuma CSP tradicional impede isso, porque o script é seu e está autorizado. A diretiva require-trusted-types-for 'script' bloqueia a atribuição direta a esses sinks.
Ela só pode ser ligada depois que o código não usa mais innerHTML. Construir os nós com createElement e textContent resolve — e como bônus elimina o bug de escape que ninguém tinha notado.
Ordem importa: primeiro tire o innerHTML, depois ligue a diretiva. O contrário quebra o site no Chrome e não avisa direito o porquê.
O risco depois da vitória
Fechada a política, aparece uma armadilha nova: quem escrever style="..." por hábito vê o estilo simplesmente não aplicar. Parece bug de CSS, não bloqueio de segurança — e a reação natural é afrouxar a política para "resolver".
Vale automatizar a defesa: um teste que falha se aparecer style= no HTML, e outro que falha se 'unsafe-inline' voltar ao cabeçalho. O comentário no código não impede o commit; o teste impede.