Qué hacemos.
Una revisión interna estructurada contra una lista establecida, cada trimestre, más inmediatamente tras cualquier actualización no trivial de dependencias o cambio en superficies de autenticación. La lista sigue el marco OWASP ASVS Level 2 + OWASP API Security Top 10 — no reclamamos certificación, pero usamos las preguntas del marco textualmente donde resulta útil. Cada pasada produce un informe fechado commit en el repositorio, respaldado por rutas de archivo y archivos de test; los hallazgos se subsanan en un commit referenciado o se aceptan como riesgo residual con motivación.
- Lista maestra — ocho áreas: autenticación y sesión, visor público + endpoint JSON-LD, rutas de escritura del panel, almacenamiento, dominios personalizados, dependencias, secretos, registro y monitorización.
- Revisión trimestral — cada fila respaldada en el archivo con rutas y archivos de test; pasa / parcial / falla por fila. Hallazgos subsanados en un commit referenciado o aceptados explícitamente como riesgo residual con justificación.
- Higiene de dependencias —
pip-auditen cada pasada.requirements.txtfijado sin rangos de versión; las actualizaciones son deliberadas y probadas.
Los controles portantes.
Afirmaciones concretas y verificables — cada una es una propiedad de código o configuración que un revisor puede comprobar.
- Cifrado en tránsito. TLS en cada superficie pública (qrregistry.io, qrregistry.eu, visores en dominios personalizados) mediante Caddy con emisión de certificados bajo demanda. La cookie de sesión es
HttpOnly+Secure+SameSite=Lax. - Cifrado en reposo. PostgreSQL + MinIO sobre hardware UE con cifrado de disco.
- Sin contraseñas. Solo magic-link. El token bruto tiene ~256 bits de entropía CSPRNG, expira en 15 minutos y se consume en el primer uso; la base de datos almacena solo un hash SHA-256, por lo que una lectura de base por sí sola no puede iniciar sesión a nadie.
- Auth diferenciada por audiencia. Las credenciales de auditor / reciclador / reparador / organismo notificado son JWT de corta duración revocables desde una única consola admin; la revocación tiene efecto en la siguiente petición, no al expirar el JWT.
- Rutas de escritura con comprobación de propiedad. Cada escritura en pasaportes, atestaciones, dominios y activos está cerrada en servidor por
row.user_id == user.id. Las filas de otros usuarios devuelven404en lugar de403— no filtramos la existencia. - Filtro Restricted-tier. Una sola función (
strip_to_visible) gobierna cada superficie de pasaporte — visor HTML, endpoint JSON-LD, feed de auditoría, PDF. Ningún campo puede filtrarse por una rama que las otras oculten. - Cadena de auditoría append-only. Cada guardado escribe una fila
passport_revisionscon hash_before / hash_after / diff estructurado.DELETE /dashboard/passports/{id}devuelve incondicionalmente403— artículo 10(4) persistencia de por vida. - Allowlist de dominios personalizados. El endpoint «ask» de TLS bajo demanda de Caddy está atado al loopback y consulta la tabla de dominios verificados; solo hostnames verificados-y-aprovisionados emiten un certificado. Invariante de reclamación única — un hostname solo puede pertenecer a un dueño.
- Disciplina de secretos. Sin secretos en código.
.enves el único inventario; las variables por servicio (base, Stripe, Resend, MinIO) son independientes. - Analítica respetuosa con la privacidad. Los eventos de escaneo registran un código de país ISO (derivado del header, nunca IP en bruto) y una clase de dispositivo gruesa — nunca una cookie de seguimiento, nunca una identidad de credencial. Documentado y expuesto en
/privacy.
Lo que no hacemos explícitamente.
No pagamos un test de penetración de terceros hasta que la puerta de compra de un cliente lo justifique. El artículo 11(h) del ESPR no define un camino de certificación ni exige test de terceros; encargar una intervención de 15-30k € compra credibilidad pero ningún <code>✅</code> regulatorio, y la revisión interna fechada documenta la misma evidencia a menor coste mientras la empresa es pequeña.
No reclamamos certificación SOC 2 o ISO 27001. La postura de nuestro proveedor de infraestructura está detrás de la línea de pie <em>«ISO 27001 aligned»</em>; la certificación les pertenece, no a Contenza K/S.
No fingimos que una revisión limpia sea la ausencia de hallazgos. La revisión del 2026-04-30 muestra cinco filas 🟡 parcial — cuatro son CVE de dependencias con versiones de corrección disponibles seguidas como bump posterior, y una es un límite de tasa a nivel de aplicación pospuesto. Ser honestos es más útil que ser aspiracionales.
Qué pueden leer.
- La lista maestra está en
docs/security-review-checklist.mden el repositorio fuente — cada fila es una pregunta que la próxima revisión debe responder con evidencia. - Cada revisión fechada está en
docs/security-review-{YYYY-MM-DD}.md— rutas de archivo, archivos de test y hallazgos, en el archivo. El historial git muestra qué cambió entre pasadas. - Cada afirmación pública en esta página mapea a una fila de la revisión más reciente.
Reportar una vulnerabilidad.
Por favor escriban a el equipo con detalles. Tratamos los reportes de seguridad como prioridad y respondemos en un día hábil. No hay todavía un programa formal de bug bounty — a nuestra escala, el reconocimiento es un agradecimiento sincero y un puesto en el changelog.
¿Preguntas sobre esta política? Utilicen el formulario de contacto — o escriban al equipo a través de los datos de la página de contacto.