Content Security Policy (CSP)
Una Content Security Policy (CSP) es un conjunto de reglas que un sitio web envía al navegador, normalmente como cabecera de respuesta Content-Security-Policy, y que indica desde qué orígenes puede una página cargar scripts, estilos, imágenes, fuentes y frames, y adónde puede enviar datos. Todo lo que la política no permite, el navegador lo rechaza antes de ejecutarlo. La página en sí sigue cargando, y por eso un error de CSP rara vez parece un error: parece una página a la que, sin hacer ruido, le falta algo.
Qué controla realmente una política
Una política es una lista de directivas, y cada una gobierna un tipo de petición. Se diseñó como segunda línea de defensa contra el cross-site scripting: si un atacante consigue inyectar marcado en tu página, el navegador sigue negándose a ejecutar scripts de un origen que la política nunca mencionó. Estas son las directivas que encontrarás primero:
- default-src — la opción por defecto. Cualquier tipo de petición sin directiva propia hereda esta, así que default-src 'self' cubre en silencio fuentes, multimedia y más, salvo que indiques otra cosa.
- script-src, style-src, img-src, font-src — de dónde puede venir cada tipo de subrecurso. 'self' significa el propio origen de la página; un nombre de host permite ese host; 'unsafe-inline' permite el código escrito directamente en la página.
- connect-src — adónde puede enviar peticiones el propio código de la página con fetch, XHR o WebSockets. Es la directiva que decide si un script puede comunicarse con el exterior.
- form-action — adónde puede enviarse un formulario. frame-ancestors — quién puede incrustar la página en un frame, el sustituto moderno de X-Frame-Options.
- Nonces y hashes — una forma de permitir un script inline concreto sin permitirlos todos: el servidor marca el script que escribió, y cualquier cosa inyectada después carece de esa marca.
Dos detalles de cómo se entrega la política confunden a mucha gente. También puede definirse en una etiqueta <meta http-equiv>, pero esa forma no admite todas las funciones, y una política en modo solo informe no puede entregarse así en absoluto. Y si una política repite la misma directiva, el navegador respeta la primera e ignora la segunda, de modo que una regla "añadida" puede no hacer nada aunque en el código parezca correcta.
Por qué un recurso bloqueado falla en silencio
Cuando el navegador rechaza una petición por una política, escribe una línea en la consola de desarrollador y sigue renderizando. Ni página de error, ni aviso, nada que un visitante o un propietario que eche un vistazo al sitio vaya a notar. Cómo queda la página después depende por completo de lo que se rechazó. Un script de analítica bloqueado deja la página idéntica píxel a píxel y tus cifras a cero. Una fuente web bloqueada recurre a una tipografía del sistema que casi nadie percibe. Una hoja de estilos o un framework de CSS bloqueado convierte una página diseñada en HTML por defecto sin estilos.
Esa dispersión es el problema práctico: el mismo tipo de infracción va de invisible a destrozar la página, y el texto de la política no te dice en qué extremo estás. Prueba la URL desplegada, no una copia local — un archivo abierto desde tu portátil suele servirse sin ninguna política, así que puede cargar todo lo que la página en producción rechazará. Esta es la razón más habitual por la que una página creada con IA se ve bien en la vista previa y mal una vez publicada.
Lo que aprendimos aplicando una a las páginas de otros
AgentCeres — el AI Growth Officer de agentceres.com — publica las páginas que sus agentes crean para los clientes, y todas se sirven bajo una política estricta: recursos solo del propio origen de la página, imágenes del origen o incrustadas directamente, formularios que solo se envían de vuelta al host, sin posibilidad de incrustarlas en otros sitios, y connect-src 'none', de modo que el código de la página puede calcular, recordar cosas en local y navegar, pero no puede hacer ni una sola petición de red. Esa última regla es la razón por la que un secreto colocado en el código de la página ni siquiera puede usarse desde la página publicada.
Cuando revisamos todas las páginas alojadas el 2026-09-04, 5 de 52 tenían al menos un recurso externo que nunca cargó. El peor caso era una página cuyo diseño completo venía de un framework de CSS cargado desde un CDN público; la política no nombra ningún host externo, así que el framework nunca llegó y la página salió publicada como texto plano sin estilos. Otras perdieron una emisora de radio o un frame incrustado. Valoramos eliminar las referencias bloqueadas al publicar y lo descartamos, porque una página recortada sigue "publicándose bien" y sigue viéndose mal; rechazarla sin más tampoco era mejor, porque la misma regla bloquearía una página por una fuente que simplemente recurre a otra. Así que el paso de publicación informa de cada referencia bloqueada junto con la directiva que la rechazará, y el arreglo se hace antes de que nadie vea la página. El veredicto se calcula a partir de la misma lista de directivas que envía el servidor, incluidas las de respaldo, así que el aviso no puede desviarse de la política.
La lección va más allá de nuestra configuración: una política que no contrastas con páginas reales es una política que rompe páginas sin avisarte. Antes de aplicarla, envíala como Content-Security-Policy-Report-Only, que informa de las infracciones sin bloquear nada, y lee lo que habría roto.
Lo que una política no puede hacer
CSP gobierna qué puede cargar una página y adónde puede conectarse. Es fácil atribuirle más que eso.
- No tiene directiva para las cookies. Un script que la política permite puede seguir leyendo y creando cookies, salvo las marcadas como HttpOnly. Las páginas que comparten un dominio padre también pueden compartir cookies, y cerrar esa puerta requiere un control aparte, no una política más estricta.
- No hace seguro el código inline. Permitir 'unsafe-inline' autoriza todo lo que esté escrito en la página, incluido lo que un atacante haya conseguido escribir ahí; para evitar eso existen los nonces y los hashes.
- No sustituye al escapado ni a la validación. Limita el daño de una inyección; no la impide. Una página que confía en la entrada del usuario sigue rota, solo que es menos explotable.
- No protege a un agente de IA de lo que lee. Una política impide que un navegador cargue un script hostil; no hace nada contra el *texto* hostil que un agente lee y sobre el que actúa, que es el problema aparte de la prompt injection.
Preguntas frecuentes
- ¿Por qué mis imágenes o fuentes cargan en local pero no en el sitio publicado?
- Casi siempre porque el host sirve una política y tu copia local no tiene ninguna. Abre la página publicada, abre la consola del navegador y busca líneas que mencionen Content Security Policy: cada una nombra la directiva que rechazó la petición. La solución es servir el archivo desde tu propio sitio o añadir el host externo a la directiva que gobierna ese tipo de archivo.
- ¿Puedo añadir 'unsafe-inline' o un comodín para que desaparezcan los errores?
- Puedes, y funcionará, y además eliminará la mayor parte de lo que la política estaba protegiendo. Nombra los hosts concretos que usas de verdad, y permite scripts inline individuales con un nonce o un hash en lugar de todos. Si no sabes qué hosts necesitas, ejecuta la política en modo solo informe durante un tiempo y lee los informes.
- ¿Afecta una Content Security Policy al SEO?
- No directamente; los buscadores no la usan para posicionar. Puede afectar al SEO de forma indirecta si bloquea algo de lo que depende la página renderizada, como un script que inserta tu contenido o tus datos estructurados, porque un rastreador que renderiza la página en un navegador suele encontrarse con el mismo rechazo. Revisa la página renderizada, no solo el código fuente.
Un equipo de crecimiento con IA que lo hace por ti
AgentCeres es un equipo de marketing con IA gestionado: tú apruebas lo que se publica. Prueba gratis de 14 días, desde $39/mes.