Skip to content

Security: TermiSenpai/Facturize

Security

docs/SECURITY.md

Seguridad

1. Modelo de amenazas (resumen)

Esta es una app de escritorio de un solo usuario que maneja: documentos financieros (facturas, con NIF/CIF, IBAN), y credenciales de terceros (API keys de proveedores de IA). Los riesgos principales no son "ataque remoto sofisticado" sino:

  • Fuga accidental de API keys (commit accidental, log, captura de pantalla).
  • Fuga de datos financieros/personales de las facturas si se suben a un proveedor de IA sin que el usuario sea consciente de ello.
  • Corrupción o pérdida del historial local (impacto en trazabilidad, no en confidencialidad).
  • Si en el futuro se distribuye a terceros: superficie de ataque de un binario firmado ejecutándose en la máquina de alguien más.

2. Gestión de credenciales (API keys)

  • Almacenamiento: exclusivamente en el almacén seguro nativo del sistema operativo (Keychain/macOS, Credential Manager/Windows, Secret Service/Linux vía keyring o el plugin oficial de Tauri). Nunca en localStorage, nunca en un JSON de configuración en disco, nunca en variables de entorno persistidas en un archivo versionado.
  • En memoria: la clave se lee del almacén seguro justo antes de la llamada HTTP y no se retiene más tiempo del necesario en estructuras de datos de larga vida.
  • En logs: cualquier log (incluido el de depuración) debe enmascarar automáticamente cualquier valor que parezca una API key (prefijos conocidos tipo sk-, AIza, etc.) — implementar un filtro de logging que redacte estos patrones por defecto, no confiar en que "no se nos olvide".
  • Rotación: la UI de Ajustes debe permitir borrar/reemplazar una clave sin dejar rastro de la anterior en ningún archivo de configuración.

3. Datos de las facturas (privacidad)

  • El usuario debe ser consciente de qué proveedor de IA está usando y qué implica: con OpenAI/Anthropic/Gemini, el contenido de la factura (datos de proveedores, importes, NIFs) sale de su máquina hacia servidores de terceros. Con el proveedor Local, no sale nunca.
  • La app debe mostrar esto explícitamente en Ajustes al seleccionar un proveedor en la nube (aviso corto, no un muro de texto legal) — transparencia, no asumir que el usuario ya lo sabe.
  • No se envía a ningún proveedor de IA nada que no sea estrictamente necesario para la extracción (no se envían metadatos del sistema, rutas de archivo, ni contenido de otras facturas del lote).

4. Dependencias

  • Revisar dependencias de Rust (cargo audit) y de npm (npm audit o equivalente) como parte del pipeline de CI, no manualmente de vez en cuando.
  • Antes de añadir una dependencia nueva, preferir crates/paquetes con mantenimiento activo y sin advertencias de seguridad abiertas conocidas.
  • Fijar versiones (Cargo.lock, package-lock.json) siempre versionados en git — builds reproducibles.

5. Manejo de archivos

  • Sanitizar nombres de archivo de entrada y salida (evitar path traversal vía ../ en nombres de archivo maliciosos, especialmente si en el futuro se procesan archivos de origen no confiable).
  • Validar que los archivos de entrada son realmente PDF/imagen antes de procesarlos (no confiar solo en la extensión) — evita que un archivo malicioso disfrazado cause comportamiento inesperado en el renderizador de PDF.
  • La carpeta de salida configurable debe validarse como ruta existente y con permisos de escritura antes de iniciar el lote, no fallar a mitad del procesamiento.

6. Red

  • Toda llamada a proveedores en la nube por HTTPS, sin excepción, sin fallback a HTTP.
  • El proveedor Local puede ser HTTP por estar en localhost/red privada — pero la app debe advertir si la URL configurada no es localhost/rango privado (posible error de configuración apuntando a algo expuesto públicamente sin cifrar).
  • Timeouts razonables en todas las llamadas HTTP — evitar que un proveedor caído cuelgue el lote entero indefinidamente.

7. Antes de hacer público el repositorio (si llega ese momento)

  • Escanear todo el historial de git en busca de secretos accidentalmente commiteados (herramienta tipo gitleaks o trufflehog) — si aparece algo, no basta con borrarlo en un commit nuevo, hay que reescribir el historial o rotar la credencial expuesta asumiendo que ya está comprometida.
  • Revisar que no haya rutas absolutas, nombres de negocio, o datos de facturas reales de prueba en el repositorio (los XML/PDF de prueba usados durante el desarrollo con datos reales de facturas no deben subirse al repo).
  • Definir una licencia explícita (LICENSE) — sin ella, un repo "público" no significa legalmente reutilizable por nadie.
  • Añadir política de divulgación de vulnerabilidades (a quién y cómo reportar un fallo de seguridad encontrado por un tercero).

8. Envío por correo (Fase 2, post-MVP)

  • La contraseña/contraseña de aplicación SMTP se guarda en el mismo almacén seguro que las claves de IA — no un mecanismo aparte, no un archivo de configuración.
  • Conexión SMTP siempre con cifrado (STARTTLS o SSL/TLS implícito) — nunca texto plano, ni siquiera en red local.
  • El correo sale a nombre del usuario (su propia cuenta), por lo que el contenido (facturas con datos fiscales) pasa por el servidor SMTP de su proveedor de correo — esto es equivalente a lo que ya ocurre hoy si el usuario reenvía facturas manualmente por email, no introduce una exposición nueva, pero merece la misma advertencia de transparencia que los proveedores de IA en la nube (sección 3).
  • Validar la dirección de destino contra un formato de email válido antes de enviar, para evitar envíos accidentales a direcciones mal escritas con datos financieros dentro.

9. Nota importante sobre el alcance de "válido"

El XML UBL que genera esta app está pensado para que Odoo lo interprete correctamente al importar — no es, ni pretende ser, una factura electrónica legalmente vinculante bajo Facturae/FACe/Veri*Factu. Si en algún momento se usa esta app o su output con fines de cumplimiento fiscal formal (no solo para rellenar Odoo automáticamente), eso requiere un análisis de conformidad legal aparte, fuera del alcance de este proyecto tal como está definido en PRD.md.

There aren't any published security advisories