Dar de alta un webhook de WhatsApp empieza con un intercambio que casi nadie mira dos veces. Meta llama a la URL que le diste con tres parámetros en la cadena de consulta: hub.mode, hub.challenge y hub.verify_token. El último es el secreto compartido que tú mismo escribiste en el panel de la aplicación. Tu servicio lo compara, devuelve el desafío, el webhook queda suscrito.

El problema llega después de responder. El formato de registro combined, el que nginx usa cuando no se especifica otro, escribe la línea de petición completa, con su cadena de consulta. Cada servidor y cada balanceador que atendió la llamada dejó tu secreto en texto plano, en un archivo que nadie trata como bóveda de secretos y que suele copiarse a un agregador.

Lo encontramos leyendo el registro de acceso de nuestra propia API mientras nacía una línea de WhatsApp. OWASP lo tiene clasificado y es tajante en lo que más cuesta aceptar: usar HTTPS no lo resuelve. El cifrado protege el tramo entre las dos puntas; el valor se escapa en los extremos, donde se escribe el registro.

La misma plataforma muestra las dos formas

Meta hace las dos cosas en el mismo canal. El saludo inicial lleva el secreto en la URL. Las notificaciones que llegan después no llevan secreto alguno: viajan firmadas en la cabecera X-Hub-Signature-256, un hash del cuerpo calculado con la clave de la aplicación. Quien recibe no necesita que el secreto viaje: lo usa de su lado para recalcular la firma y comparar.

Esa diferencia no es de gusto. Una cabecera no entra en el registro de acceso, no queda en el historial del navegador y no se reenvía en el Referer. Un parámetro de la URL hace las tres cosas.

Cuando el diseño ajeno no se puede cambiar

Apagar el registro de acceso no sirve: es justo lo que te dice quién llamó y con qué respuesta cuando un alta se queda a medias. Lo que está hoy en producción tacha en el punto de escritura: un filtro reemplaza por asteriscos el valor de los parámetros que llevan secreto y deja la línea intacta, con su método, su ruta y su código de respuesta.

Queda la parte que se olvida. Un secreto que ya viajó en una URL está quemado. Tacharlo de ahora en adelante no borra los registros de ayer: hay que rotarlo y volver a apuntar la suscripción al valor nuevo.

Qué revisar en tu propio sistema

Busca en tus registros los nombres token, secret, apikey y password con un valor al lado: cada uno que aparezca es un secreto que hay que rotar, no solo tachar. Y cuando el proveedor te deje elegir, firma el cuerpo con una cabecera.

Escribimos desde la operación de agentes de WhatsApp en producción (casos), y lo que aplicamos en ese canal está en seguridad. Del mismo canal, otra regla que no se delega al modelo: no toda línea de WhatsApp puede iniciar una conversación. Del mismo cuaderno de hallazgos, uno que no se ve hasta que llegan dos escrituras a la vez: una clave foránea es un candado. Y otro secreto que viaja en la URL a propósito, la firma de un archivo, con un problema distinto: la red del cliente bloquea el dominio y el archivo no llega.