
Si hay algo que aprendí administrando servidores en Chile es que los problemas más feos no vienen del atacante de turno ni del ransomware de moda. Vienen de la confianza ciega. De creer que algo es "boring technology" y dejarlo correr sin mirarlo dos veces.
Tailscale acaba de publicar un postmortem que debería ser lectura obligatoria para cualquiera que administre infraestructura. No es una historia de hacking espectacular. Es peor: es la crónica de cómo una base de datos SQLite, usada de la manera correcta, empezó a corromperse una y otra vez durante seis meses.
El enemigo estaba adentro
Desde 2022, Tailscale usa SQLite como base de datos principal de su plano de control. Un solo proceso Go escribe a la base de datos. Sin concurrencia salvaje, sin clusters distribuidos, sin microservicios peleándose por el lock. Exactamente como SQLite está diseñado para usarse.
Hasta que en agosto del año pasado, una pipeline de backups reportó corrupción. Revisaron, repararon, siguieron. Luego pasó de nuevo. Y otra vez. En total: 19 incidentes de corrupción en seis meses.
¿La causa? Un bug de 16 años escondido en el proceso de checkpoint del WAL (Write-Ahead Logging). Un error tan profundo que pasó desapercibado desde 2008. Eso es antes de que yo terminara la enseñanza media, por si necesitas contexto.
La forense que no querían hacer
Lo que me impactó de la historia no es solo el bug, sino cómo lo cazaron. No había forma de reproducirlo sintéticamente. No estaba atado a una shard específica, ni a un cliente, ni a una hora del día. A veces pasaban semanas sin nada. Después volvía como regalo de Navidad no deseado.
Contrataron soporte profesional de los desarrolladores de SQLite —una decisión inteligente que poca empresa toma— y empezaron a tirar telemetría pasiva en producción. Monitorear una base de datos en vivo para atrapar una corrupción que ocurre al azar es el tipo de trabajo que te hace cuestionar tus decisiones de vida. Pero funcionó.
La pista clave vino de un pipeline de logs de transacciones. Descubrieron que en dos incidentes, datos escritos y confirmados por una transacción simplemente desaparecían para transacciones posteriores. Un write que se evaporaba sin error. Eso debería ser imposible en cualquier base de datos que respete ACID.
¿Qué significa esto para nosotros?
SQLite sigue siendo una base de datos excelente. Pero esta historia me hace pensar en todas las veces que elegí una herramienta "porque es aburrida y funciona" sin tener un plan real para cuando deje de funcionar. El "boring technology" necesita monitoreo aburrido. Backup aburrido. Logs aburridos. Todo lo opuesto a la magia sin infraestructura que venden algunos.
También me hace reflexionar sobre la telemetría. Tailscale no pudo resolver este bug con un parche rápico ni con un rollback. Necesitaron meses de análisis forense, datos de producción y conversaciones directas con los autores del software. Eso cuesta plata. Eso carga la pega. Pero es la diferencia entre un incidente que resolvés y uno que te hace perder clientes.
Si usas SQLite en algún proyecto crítico —y seamos honestos, muchos de nosotros lo usamos sin admitirlo— revisá tu estrategia de backups. Corré PRAGMA integrity_check de vez en cuando. Y si ves corrupción que no tiene sentido, no asumas que es tu culpa. A veces el bug tiene 16 años y está esperando que alguien lo encuentre.
Fuente de inspiración: How we tracked down a 16-year-old SQLite bug
