Por qué pegar un enlace de un solo uso en un chat con vista previa no gasta siempre la lectura
Que aparezca una tarjeta bajo el mensaje no significa que el destinatario ya haya leído el texto cifrado. Para dibujar esa tarjeta, Slack, WhatsApp, Discord o Teams envían un GET HTTP a la página de llegada. Esa petición suele leer el título y una línea de descripción. No pulsa Abrir y ver y no envía la clave que va después de #. Este artículo separa «salió la tarjeta» de «se ha gastado una lectura» y recorre una comprobación que puedes hacer con un enlace de prueba. No es la guía del formulario de creación.
Primero, qué capa lee la tarjeta
Este artículo solo responde por qué un enlace de un solo uso pegado en un chat con vista previa no tiene por qué estar ya gastado. No es el formulario de enlace de un solo uso ni el texto sobre «por qué # no entra en los registros del servidor».
Qué capa lee de verdad la tarjeta
La tarjeta aparece unos segundos alrededor del envío. La petición sale de los servidores del chat, no del dedo del destinatario.
Pegas una dirección con forma https://…/s.html?id=…#… en Slack, WhatsApp, Discord o Microsoft Teams y, a menudo, bajo el cuadro de mensaje o el propio mensaje sale una tarjeta pequeña: un título, una línea de descripción, a veces un icono. Mucha gente lee esa tarjeta como «el enlace ya se ha abierto». El orden es el inverso. El chat primero envía un GET HTTP a esa dirección, extrae del HTML el og:title, el og:description o un <title> normal, y después dibuja la tarjeta. El destinatario puede no haber pulsado nada todavía.
Slack lo tiene escrito. Por defecto, los mensajes con una URL completa se expanden en una vista previa. El robot que hace esa expansión se identifica como Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots). En Unfurling links in messages Slack llama a ese tratamiento «classic link unfurling»: rastrea la URL y adjunta una vista previa. En la misma empresa, la página Slack Robots dice que el expansor pide lo menos posible de la página (con cabeceras HTTP Range) y busca etiquetas oEmbed, Twitter Card y Open Graph. Solo vuelve a pedir un archivo de imagen, vídeo o audio si una etiqueta apunta a él, para comprobarlo. Las respuestas se almacenan en caché unos 30 minutos. La página no dice «ejecutar el JavaScript de la página» ni «pulsar un botón por el usuario».
Cuando un navegador —o un robot de vista previa que se comporta como uno— emite ese GET, lo que va después de # no forma parte de la línea de petición. El RFC 3986 §3.5 de la IETF define el fragmento como identificación en el cliente. El servidor no lo usa al procesar el URI. Así que, aunque el robot copie la cadena entera que ves en el cuadro de mensaje, la petición que llega a UsePwd suele detenerse en s.html?id={id}. Por qué la clave no aparece en los registros de acceso lo cuenta el artículo Por qué el fragmento # de una URL no aparece en los registros del servidor. Aquí falta la capa siguiente: un GET que nunca llevó la clave, ¿cuenta como «una lectura»?
La pregunta útil no es «¿el chat ha visto esta URL?». Es «¿este GET ha llegado a la API del texto cifrado?». Una tarjeta solo demuestra que se ha leído el título. Si el texto cifrado sigue ahí es otra comprobación.
Por qué el primer GET no es una lectura
Si una herramienta trata «pedir el texto cifrado» y «abrir la página de llegada» como la misma petición, el bot de vista previa gastará la única lectura. Separa esos pasos y dejan de ser el mismo gesto.
Muchos enlaces de un solo uso cuelgan el secreto de la misma URL que el bot de vista previa pide con GET. El robot pide una vez; el servidor devuelve el cuerpo y borra el registro. El destinatario abre después «ya leído» o un 404. Ese fallo es frecuente. No es que Slack «queme el secreto a propósito». Es una implementación que trata un GET almacenable en caché —el método que el RFC 9110 sigue llamando seguro— como la acción que destruye el texto cifrado. Herramientas en español lo dicen con las mismas palabras: un paso intermedio o un clic humano evita que la previsualización del chat o un escáner de URL «consuma las visitas» o «queme» el enlace antes de tiempo.
El enlace de un solo uso de UsePwd parte el trabajo en tres pasos. Al crear, la pestaña actual cifra con Web Crypto y AES-256-GCM. El texto en claro no supera los 32 KB. Los únicos campos que se suben son el texto cifrado, un plazo y un número de lecturas. El plazo puede ser 1 hora, 24 horas, 7 días, o «destruir solo al leer», sin reloj. Las lecturas van de 1 a 10; el valor por defecto es 1. La URL compartida tiene la forma s.html?id={id}#{key}. Crear y leer se abren al instante: nadie se registra. El servidor solo guarda texto cifrado. No ve el texto en claro y no hay cuenta con la que recuperar el secreto por usuario.
Cuando el destinatario abre la página de lectura, la pestaña pregunta primero a /api/secrets/{id}/status si el texto cifrado sigue ahí. Esa llamada devuelve active, burned o expired. No suma una lectura y no borra el registro. Solo después de Abrir y ver el navegador pide /api/secrets/{id}, recupera el texto cifrado y lo descifra en local con la clave que va después de #. Al alcanzar el número fijado al crear, el servidor borra el texto cifrado; una petición posterior devuelve 410. Un bot de vista previa que se queda en el HTML de llegada suele no tener la clave y no pulsa ese botón.
Devuelve la página de lectura estática. El título es «Abrir un enlace de un solo uso». No lleva texto en claro. Las tarjetas de vista previa suelen quedarse aquí.
Solo responde si sigue ahí, si está destruido o si ha caducado. Repetir la consulta no suma una lectura.
Esta es la llamada que cuenta como una lectura. Tras el valor por defecto de 1, el texto cifrado se borra. En la página de lectura eso es Abrir y ver.
La página de lectura también escribe una frase que puedes comprobar en el acto: el botón «puede gastar una lectura». Sin scripts no hay camino de descifrado; un bloque <noscript> lo dice. Un bot de vista previa que solo lee HTML y no ejecuta JavaScript ni siquiera envía la consulta de estado. Si el navegador interno de la app sí ejecuta scripts, se detiene en «El texto cifrado sigue aquí» hasta que alguien pulse el botón.
Qué bots llegan y qué se llevan
Muchos productos pueden dibujar una tarjeta. Lo que se llevan es la cabecera de la página, no la clave que va después de # y no el texto en claro ya descifrado.
El robot de expansión de Slack, el rastreador de incrustaciones de Discord y la petición que WhatsApp o Microsoft Teams hacen en el servidor para armar una tarjeta son la misma clase de captura: GET de la página y búsqueda de un título y una descripción en el HTML. Discord se identifica como Mozilla/5.0 (compatible; Discordbot/2.0; +https://discordapp.com). Los análisis públicos de Discordbot coinciden en un límite que puedes tomar como hipótesis de trabajo: parsea el HTML que devolvió el servidor y no ejecuta JavaScript. Slack es explícito en otro límite. Tras probar robots.txt, dejó de tratarlo como un rastreador de búsqueda, porque expandir un enlace es «actuar en nombre de una persona», no recorrer el sitio. Poner noindex en la página de lectura puede impedir que los buscadores la indexen. No impide la tarjeta en el canal.
La página de lectura de UsePwd es una vista temporal de texto cifrado. Lleva noindex, nofollow y no está en el mapa del sitio. El título del documento está fijado como «Abrir un enlace de un solo uso». La descripción solo dice que el descifrado termina en esta pestaña y que la clave va después de #. Si aparece una tarjeta, el canal ve esa frase genérica: no la contraseña, el token ni el texto del ticket que escribiste. Eso puede ser cierto a la vez que «el registro de acceso no tiene el fragmento». La tarjeta demuestra que alguien ha hecho GET de la página de llegada. El registro sigue sin tener la clave que va después de #.
Slack indica que el resultado de expandir la misma URL se guarda unos 30 minutos. Pegar dos veces el mismo enlace de prueba en un canal, en una ventana corta, puede no producir una segunda captura. Para comprobar «¿ha venido un bot?», busca en tus propios registros de acceso un User-Agent como Slackbot-LinkExpanding, Discordbot o WhatsApp. No te quedes mirando cómo se refresca la tarjeta. Un GET a s.html sigue sin significar que se haya llamado a /api/secrets/{id}.
Cuándo sí se gasta de verdad una lectura
«No siempre se gasta» no es «nunca se gasta». La visita que puede pulsar Abrir y ver es la que llega a la capa del texto cifrado.
El consumidor habitual es el destinatario: abre el enlace completo, ve «El texto cifrado sigue aquí» y pulsa Abrir y ver. El número por defecto es 1. Tras esa petición correcta, el servidor borra el texto cifrado. Volver a abrir el mismo enlace muestra «Ya destruido». Si al crear pones 2 lecturas o más, las peticiones anteriores dejan el texto cifrado en su sitio hasta que el contador llega al tope. El plazo también borra: 24 horas por defecto, o 1 hora o 7 días. «Destruir solo al leer» borra por número, no por reloj.
La segunda clase es un entorno que ejecuta scripts y simula un clic. Algunas pasarelas de seguridad del correo y algunos entornos aislados de enlaces abren la URL en un navegador separado. Algunas también pulsan el botón principal. Eso ya no es «dibujar una tarjeta». Es una segunda visita con forma humana. Si el entorno aislado pulsa Abrir y ver, se gasta la lectura y el destinatario ve después el estado destruido. Contrástalo con el informe de esa pasarela. No se puede deducir de la tarjeta del chat.
La tercera clase es publicar la propia URL de la API del texto cifrado. La dirección de la página de lectura es s.html?id=. La llamada que gasta una lectura es /api/secrets/{id}. Un usuario corriente no copia la segunda. Si alguien pega esa URL de API en un canal que genera vista previa, y el producto trata el primer GET como la petición del secreto, la lectura se puede gastar al previsualizar. La forma de compartir de UsePwd no es esa dirección. La página de creación copia el enlace de lectura con #.
Que la vista previa no haya gastado una lectura no significa que el secreto exista solo para el destinatario. El chat sigue guardando la URL completa. Un administrador del espacio de trabajo puede exportar el historial. El límite de lecturas controla cuánto vive el texto cifrado en el servidor. No controla quién puede seguir abriendo esa dirección desde el canal.
Cómo comprobar la vista previa en el acto
El objetivo no es demostrar que «ningún chat del mundo leerá nunca el texto cifrado». Es demostrar que, después de aparecer la tarjeta, la API del texto cifrado aún no se ha llamado.
-
01
Prepara un texto de prueba que no uses para un traspaso real
No escribas una API key en uso ni una contraseña de acceso. Abre el enlace de un solo uso, escribe
PreviewCard-20260905, deja las lecturas en 1 y el plazo en 24 horas. La página se abre al instante, sin registro. Estos pasos sirven para comparar una tarjeta con las API. No son una forma de pasar esta cadena a un compañero como secreto real. -
02
Guarda el enlace completo y abre tú la página de lectura
Tras crearlo deberías ver
s.html?id=y un tramo#. Abre ese mismo enlace en el navegador actual. La página debería detenerse en «El texto cifrado sigue aquí» y mostrar Abrir y ver. Aún no pulses el botón. Pulsa F12 y abre el panel Network. Deberías ver una petición a/api/secrets/{id}/status. Aún no deberías ver una petición del texto cifrado a/api/secrets/{id}sin el sufijo/status. -
03
Pega el mismo enlace en un canal de prueba que genere vista previa
Usa un canal de Slack que solo veas tú, un mensaje a ti mismo en WhatsApp o Discord, u otra sala de prueba. Espera la tarjeta. El título debería acercarse a «Abrir un enlace de un solo uso». No debería mostrar
PreviewCard-20260905. Recarga la página de lectura, o abre el mismo enlace en una ventana que no haya pulsado el botón. Debería seguir diciendo «El texto cifrado sigue aquí». Si ya dice «Ya destruido», otra visita ha llegado a la API del texto cifrado. Eso no es «la tarjeta equivale a una lectura». -
04
Si tienes registros de acceso, contrasta el User-Agent
En la ventana de la vista previa sueles ver un GET a
/es/s.html?id=…. El User-Agent puede contenerSlackbot-LinkExpanding,DiscordbotoWhatsApp. En la misma ventana no deberías ver una recuperación correcta de/api/secrets/{id}. Slack guarda en caché la misma URL unos 30 minutos, así que un segundo pegado en esa ventana puede no producir una segunda captura. -
05
Solo entonces pulsa Abrir y ver, y confirma que se gasta la lectura
Pulsa el botón ahora. El panel Network debería mostrar la petición del texto cifrado y la página debería enseñar el texto de prueba. Ciérrala y abre el mismo enlace otra vez. Debería decir «Ya destruido». Este paso existe para que «después del botón» y «después de la tarjeta» sean dos estados que has visto. Tira el enlace cuando termines. No se lo reasignes a un destinatario real.
Si solo necesitas pasar una clave nueva a otra persona, no pegues el texto en claro en un canal «para ver una tarjeta». Separa el texto de prueba del secreto real. El traspaso real sigue yendo por el enlace de un solo uso. El segundo riesgo tras una filtración de variables de entorno está en Tras una filtración de variables de entorno, por qué la clave nueva no debe volver al chat. Aquel artículo es «no pegues la API key en un historial que se busca». Este es «después de pegar el enlace, en qué capa se detiene la vista previa».
Qué deja el chat si el contador no baja
Leer «la tarjeta no ha quemado el texto cifrado» como «este enlace ya ha salido del canal» se deja fuera unos límites que también puedes comprobar.
El chat guarda la dirección entera que pegaste. Quien pueda buscar el historial, exportar un espacio de trabajo o abrir una copia de seguridad puede volver a abrir la página de lectura. Mientras queden lecturas, quien abra después puede pulsar Abrir y ver y ver el texto en claro. Cuando el contador se agota, el historial conserva un enlace ya destruido más el título que mostró la tarjeta. Una exportación de administrador no puede restaurar el texto cifrado que el servidor ya ha borrado. Tampoco puede deshacer «este canal tuvo alguna vez la URL completa».
Las capturas y los reenvíos son otra copia. Si alguien captura el texto en claro después de una lectura correcta, o reenvía el enlace a otra sala que genera vista previa, el límite pasa de «este GET» a «quién está en el siguiente salto». El enlace de un solo uso limita cuánto vive el texto cifrado en el servidor y cuántas veces se puede pedir. No impide que el destinatario haga una captura. UsePwd no tiene cuentas ni almacén de contraseñas, y no puede recuperar un enlace perdido por usuario. Conservarlo a largo plazo o sincronizarlo entre dispositivos corresponde a un gestor de contraseñas. La identidad está en Acerca de.
Los archivos son un tercer camino. Una copia local de un solo archivo de hasta 5 GB pasa por cifrar archivo, que escribe .lock / .enc. El archivo no se sube por defecto. Genera la propia contraseña en el rango de 6 a 128 caracteres en el generador y comprueba la fortaleza en el comprobador. Esas páginas, como este artículo, se abren al instante. No leas «la vista previa no ha gastado una lectura» como «pégalo en cualquier canal y es seguro». El historial del canal y la captura de vista previa no son la misma capa.
Lo que se pregunta después de una vista previa
Estas cuatro respuestas se quedan en el límite de este artículo. No repiten los botones de la página de creación.
Al terminar, comprueba una tarjeta de vista previa
Este artículo responde por qué una vista previa no consume siempre la lectura. Para generar un enlace de prueba que no uses en un traspaso real y pegarlo en un canal de prueba, abre el enlace de un solo uso. No te registres antes.