Auditoría de seguridad
Esta página publica los resultados de las auditorías de seguridad y de salud del código de a11yequitas.org. Las auditorías se ejecutan en cada lanzamiento.
Última ejecución: 2026-07-19 (salud del código + escaneo de dependencias; las demás categorías se ejecutaron por última vez el 2026-05-25). Próxima ejecución: con el próximo lanzamiento.
Metodología
- vitest: aserciones de seguridad para componentes y rutas. El sitio no inserta HTML peligroso fuera de los scripts en línea aprobados, no carga scripts externos más allá del stub de analítica y no filtra datos entre orígenes.
- Fallow: herramienta de inteligencia de código (Rust). Mide código muerto, duplicación, complejidad ciclomática, tamaño de unidad y acoplamiento. Produce una puntuación de salud de 0 a 100 con calificación con letra. Integrada en la lista de verificación de cada lanzamiento.
- pnpm audit: escaneo de vulnerabilidades en dependencias, ejecutado en cada lanzamiento mediante
pnpm run audit(encadenado con Vitest y Fallow). Los avisos de severidad alta y crítica bloquean el lanzamiento. - Cabeceras HTTP de seguridad: verificadas mediante comprobación automática e inspección manual. Cabeceras objetivo:
Content-Security-Policy,Strict-Transport-Security,X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Permissions-Policy.
Calificaciones por categoría
| Categoría | Fecha | Calificación | Hallazgos |
|---|---|---|---|
| Salud del código (Fallow) | 2026-07-19 | B (79) | Puntuación 79 / 100 obtenida con fallow health --score (fallow-cli 2.85.0). El análisis de código muerto está completamente limpio: 0 incidencias (1 supresión documentada, 0 supresiones obsoletas), 110 puntos de entrada, archivos muertos 0,0 %, exportaciones muertas 0,0 %, sin dependencias circulares. Métricas: 24.940 líneas analizadas, mantenibilidad media 95,3 (buena), complejidad ciclomática media 1,9 / p90 4, 42 de 638 funciones por encima del umbral de complejidad. La duplicación reportada es del 49,1 % en 65 archivos — la gran mayoría corresponde al espejado intencional de páginas inglés/español (cada page.es.tsx traducida a mano es un clon estructural deliberado de su página inglesa hermana), incluido ahora en el análisis al declararse las páginas españolas como puntos de entrada; es arquitectura bilingüe, no deuda de copia-y-pega. Hallazgos previamente abiertos, todos resueltos el 2026-07-19: public/static/styles.css está referenciado por cinco páginas HTML heredadas activas (excluido del análisis del grafo JS con motivo documentado); las exportaciones de tipo AIDoc/SRReport dejaron de exportarse (uso solo interno al archivo); /pagefind/pagefind.js se añadió a ignoreUnresolvedImports (se genera en tiempo de compilación, esperado). La puntuación numérica se actualiza cuando la auditoría se ejecuta en el servidor de producción. |
| Escaneo de dependencias (pnpm audit) | 2026-07-19 | A | 0 críticas, 0 altas, 0 moderadas, 0 bajas. Seis avisos en dependencias transitivas de desarrollo (2 altas: tmp path traversal GHSA-ph9p-34f9-6g65, vite omisión de fs.deny GHSA-fx2h-pf6j-xcff; 3 moderadas: uuid GHSA-w5hq-g745-h8pq, launch-editor GHSA-v6wh-96g9-6wx3, js-yaml DoS por claves de fusión; 1 baja: tmp enlace simbólico GHSA-52f5-9888-hmc6) se resolvieron el 2026-07-19 mediante sobrescrituras de pnpm con alcance acotado — el uso de la API por parte de cada paquete consumidor se verificó como compatible antes de forzar cada actualización. El aviso previo de postcss (GHSA-qx2v-qp2m-jg93) sigue resuelto por la sobrescritura anterior. |
| Cabeceras HTTP de seguridad | 2026-05-25 | B+ | HTTPS se aplica: HTTP en texto plano devuelve 301 a https://a11yequitas.org/. La respuesta en producción incluye Content-Security-Policy, Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, X-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN, Referrer-Policy: strict-origin-when-cross-origin y Permissions-Policy: camera=(), microphone=(), geolocation=(). Seguimiento: aumentar HSTS a max-age=63072000, añadir interest-cohort=() y mantener frame-ancestors 'none' como control efectivo contra encuadres. |
| Política CSP | 2026-05-25 | B | Política activa en la respuesta HTTPS en producción: default-src 'none'. La política limita los scripts a código en línea del mismo origen, más Umami y Cloudflare Insights. Permite estilos, imágenes, fuentes, workers y Pagefind del mismo origen. Fija base-uri 'self', form-action 'none' y frame-ancestors 'none'. Siguientes pasos: primero, migrar los scripts en línea a nonces o hashes; luego, eliminar 'unsafe-inline' y 'wasm-unsafe-eval' de script-src. Revisar los requisitos de imágenes de los mosaicos del mapa antes de endurecer img-src. |
| Superficie XSS / inyección | 2026-05-25 | A | Exportación estática: sin renderizado del lado del servidor, sin envíos de formularios en vivo, sin eval, sin Function(), sin document.write y sin .innerHTML = directo en el código de producción. Las coincidencias en pruebas se limitan a src/__tests__/static-html.aaa.test.ts (document.write(html) + w.eval(axeSource)), usadas para cargar HTML estático generado e inyectar axe en el DOM de prueba. 12 usos de dangerouslySetInnerHTML: 11 son literales de cadena para JSON-LD inline / restauración de tema; 1 (los extractos de Pagefind en SearchDialog) inyecta HTML del mismo origen generado en tiempo de compilación; el límite de confianza está anotado en el código. |
| Scripts de terceros | 2026-05-25 | A | Un único script de analítica Umami autoalojado (defer, sin cookies). No hay otro JavaScript de terceros. Sin fuentes ni iconos cargados desde CDN. Todos los enlaces con target="_blank" llevan rel="noopener noreferrer". |
| Privacidad / recopilación de datos | 2026-05-25 | A | Sin cookies. No se recopila información personal identificable. Las preferencias de fuente y tema se guardan únicamente en localStorage (cadenas, sin identificadores). Sin fetch de red en producción (la única solicitud POST en desarrollo dentro de ScreenReaderChecklist está controlada por NODE_ENV !== "production"). |
| Regresión de accesibilidad (Vitest + axe) | 2026-05-25 | A | 70 / 70 páginas pasan las verificaciones automáticas de axe-core para WCAG 2.2 AAA en happy-dom (un subconjunto de la AAA completa — sigue siendo necesaria una revisión manual y con tecnología de asistencia). Fija los hallazgos de Playwright a nivel de archivo. Se ejecuta mediante pnpm run audit:vitest (23,17 s). |
| Auditoría de accesibilidad (Playwright + axe + Alfa) | 2026-05-25 | A | 352 / 352 pruebas superadas. 32 rutas × axe (6 combinaciones de tema y fuente) + Alfa por ruta + aserciones estructurales (lang, h1, título, enlace de salto). |
Postura estática del sitio
a11yequitas.org es una exportación estática completa de Next.js. El sitio no ejecuta código en el servidor. No usa base de datos. No tiene autenticación. No procesa envíos de formularios. La superficie de ataque se limita a:
- Riesgo de inyección del script de analítica de terceros (un único script, cargado con defer)
- Capa de CDN / hospedaje (Podman + Nginx sobre Rocky Linux)
localStorage: solo almacena cadenas con preferencia de fuente y tema; sin datos sensibles
Hallazgos conocidos
- postcss < 8.5.10 (resuelto 2026-05-24): XSS en la salida de stringify de CSS (GHSA-qx2v-qp2m-jg93). Corregido mediante una sobrescritura de pnpm en
pnpm-workspace.yaml; ahora todos los consumidores resuelven apostcss 8.5.15. - Salud del código en Fallow: unit_size: los componentes de página todavía incluyen entre 200 y 400 líneas de JSX por archivo. El boilerplate del envoltorio ya está extraído en
ProseArticle; queda dividir las secciones inline de cada página (alertas, tablas, listas) en subcomponentes co-ubicados. 42 de 638 funciones analizadas siguen por encima del umbral de complejidad (el universo analizado creció el 2026-07-19 al declararse como puntos de entrada las páginas españolas hermanas y los scripts de línea de comandos). En seguimiento. - Salud del código en Fallow: duplicación 49,1 %: la cifra principal subió el 2026-07-19 porque las páginas españolas traducidas a mano (
page.es.tsx) se añadieron al análisis como puntos de entrada; cada una es un clon estructural deliberado de su página inglesa hermana, así que la mayor parte de la duplicación reportada es arquitectura bilingüe intencional, no deuda de copia-y-pega. El resto genuino de clones de contenido (listas de criterios WCAG, marcado de tablas accesibles, secciones de «Interacción con el teclado» compartidas entre tutoriales) sigue requiriendo componentes de contenido compartido (por ejemplo,<WcagBulletList>) y está pautado para un ciclo de refactor de contenido. - Exportaciones y archivos no usados detectados por Fallow — resueltos el 2026-07-19:
public/static/styles.cssestá referenciado por cinco páginas HTML heredadas activas (excluido del análisis del grafo JS con motivo documentado); las exportaciones de tipoAIDocySRReportdejaron de exportarse (uso solo interno al archivo); los scripts de línea de comandos bajoscripts/y las páginas españolaspage.es.tsxse declararon como puntos de entrada. El análisis de código muerto ahora reporta 0 incidencias. - Importación no resuelta en Fallow (esperada, suprimida por configuración):
/pagefind/pagefind.jsse genera en tiempo de compilación dentro deout/pagefind/y se carga dinámicamente desde el mismo origen. Se añadió aignoreUnresolvedImportsen.fallowrc.jsonel 2026-07-19 con este motivo. No es un hallazgo de seguridad. - Inyección de extractos de Pagefind en SearchDialog (bajo):
dangerouslySetInnerHTMLrenderiza el HTML de extractos del índice de Pagefind. La fuente es el índice del mismo origen, construido a partir del contenido propio del sitio; no se indexa contenido de terceros. El límite de confianza está documentado en el código. Si el índice llegara a ingerir contenido externo, se debe sanear antes de renderizar.
Reportar un problema de seguridad
Para reportar un problema de seguridad, contacte a A11y Equitas a través de a11yequitas.org. Por favor, no abra incidencias públicas sobre vulnerabilidades de seguridad sin resolver.
