Skip to content
reader.me

Notas técnicas

Modelo de seguridad

Qué protege reader.me y qué no, y cómo se tomaron decisiones como "usar AES-128 en lugar de AES-256" o "mantener 'unsafe-inline' en el CSP". Escrito para reviewers de seguridad y lectores escépticos — sin marketing.

Modelo de amenazas

reader.me es una single-page web app que corre dentro del navegador del usuario. La superficie de amenaza está moldeada por eso.

defendemos contra

  • Fuga del documento via upload. Toda la arquitectura está construida para hacer estructuralmente imposible subir documentos.
  • Fuga via JS de terceros. El CSP restringe script-src a 'self' + una pequeña allowlist.
  • PDFs maliciosos contra PDF.js. Pinneado a ≥4.2.67 (fix de CVE-2024-4367) con isEvalSupported: false y enableXfa: false.
  • Brute-force de contraseña en PDF Proteger. AES-128 con IV aleatoria — elección conservadora frente a AES-256 con debilidades conocidas (Cryptanalysis of PDF Security Handler, 2020).
  • XSS via nombre de fichero. Filenames renderizados como texto; metadata escrita como PDFHexString.fromText.
  • Presión de memoria en ficheros grandes. Operaciones >20 MB dispatch a Comlink Web Worker con transferables zero-copy.

No defendemos contra

  • Extensiones del navegador con keylogger / screen recorder. Una extensión con activeTab puede leer todo lo que leemos. Fuera de nuestro perímetro.
  • Compromiso a nivel OS. Si la máquina está rooteada, el atacante ya tiene el fichero.
  • Operador de red haciendo MitM con CA colaboradora. Un actor estado-nación puede hacer cosas malas a cualquier HTTPS.
  • Side channels de CPU. Spectre/Meltdown — confiamos en mitigaciones del navegador.

Content Security Policy

El CSP de Reader vive en reader-web/public/_headers y lo aplica Cloudflare Pages en cada respuesta. Highlights:
  • default-src 'self' — todo fetch va por defecto al primer-party.
  • script-src 'self' 'wasm-unsafe-eval' 'unsafe-inline' + orígenes de analytics. La relajación 'unsafe-inline' es requerida por la hidratación de Astro; elegida en Fase 1 porque hashear los inlines costaba ~600 ms de LCP en móvil.
  • connect-src restringido a 'self' + analytics + CDN de Tesseract. Ningún endpoint acepta datos de documentos.
  • frame-ancestors 'none' — clickjacking imposible.
  • upgrade-insecure-requests — todo HTTP forzado a HTTPS.

Política de dependencias y respuesta a CVE

Tres motores son críticos para la seguridad: PDF.js, pdf-lib y Tesseract.js. Nuestra política:
  • Rangos pinneados en package.json con tilde, patch releases via Dependabot.
  • SLA de parche para CVE crítica: 72 h desde la divulgación pública cuando la CVE afecta caminos de código que ejercitamos.
  • Tesseract WASM y trained data self-hosted en /tesseract/ para evitar dependencia de CDN externo en bytes críticos.
  • Verifica la promesa de privacidad en tu navegador — DevTools → Network mientras corre cualquier tool. Cero peticiones de documento. Ver la receta de 30 segundos.

Quality gates en CI

  • Engine purity check — fuerza que pdf-engine/core/** nunca toque DOM, fetch, window, navigator.
  • Tests unitarios — Vitest cubre cada función pura al 97% líneas / 100% funciones.
  • Tests end-to-end — Playwright en flows reales de browser por cada PR.
  • Accesibilidad — axe-core asserta cero violaciones WCAG 2.1 / 2.2 AA en 8 rutas (incl. RTL).
  • Lighthouse CI — perf ≥95, a11y =100, SEO =100 en cada push a main.

Reportar una vulnerabilidad

Si encuentras un issue de seguridad, divúlgalo responsablemente via email para no poner en riesgo a los usuarios con un reporte público:

[email protected] — incluye descripción y pasos mínimos de reproducción.

Apuntamos a confirmar en 48 h y parchear críticas en 72 h. Se da crédito en el changelog salvo que prefieras anonimato.

Relacionado

reader.me es una idea de David Carrero, construido en Color Vivo Internet S.L.