Revisión de contraejemplos: F0 devuelve 0/3 en ambos modos HTML; el texto aria-label de F1 aparece 3/3 veces en HTML acotado; el nodo display:none de F2 aparece 3/3 veces en ambos modos. Solo se observa el texto devuelto por Fetch, no el comportamiento del agente ni la eliminación de sesiones remotas.
Sonda de contraejemplos · El texto devuelto por Fetch no es una prueba de obediencia del agente. Ejemplos de fixtures traducidos del chino original.

Con el rápido avance de los agentes de IA, también empezamos a probar herramientas nuevas como Meta Muse, ChatGPT Dots y Claude Duet. Tomar el control de un navegador, iniciar sesión en un panel interno y completar un flujo puede parecer cuestión de unos pocos pasos. Pero cuando veo la pantalla navegar por sí sola, me surge una pregunta menos vistosa: al terminar el flujo, ¿adónde fueron los datos de la cuenta entregados a la nube? ¿Cuándo termina la sesión iniciada? Si una herramienta secuestra ese estado o una página oculta texto que intenta cambiar los hechos de un pedido, ¿quién asume la responsabilidad? Plantearlo no presupone que los agentes en la nube sean inseguros; busca aclarar el límite de confianza antes de delegar trabajo real.

Las demostraciones de producto suelen mostrar que un flujo funciona, pero rara vez responden a fondo estas preguntas. Para esta revisión elegí TinyFish y acoté el problema: examiné qué devuelve TinyFish Fetch a partir de seis páginas HTML con pedidos ficticios y revisé el código fijado de AgentQL MCP, la documentación del SDK, la documentación de sesiones de navegador remoto y las condiciones separadas de ambos servicios.

Primero, el límite de la evidencia: lo observado en esta ronda es que el modo de extracción cambia el texto devuelto por la herramienta. No entregué ese texto a un agente, así que no permite concluir si un agente obedecería una instrucción falsa. No se probaron cuentas reales, cookies, sesiones remotas ni la eliminación de datos remotos.

Obtener una página, pasar su contenido a un modelo, dejar que el modelo decida el siguiente paso y mantener remotamente el estado de inicio de sesión de una cuenta son capas distintas. Fetch puede devolver texto que una persona no ve, pero eso no significa que un modelo vaya a seguirlo. Permitir que un agente haga clic según el contenido de la página o entregarle una sesión autenticada son otras barreras de riesgo que esta ronda no probó.

Límites de la evidencia

MedidoRevisión estáticaNo probado
Texto devuelto por TinyFish Fetch: 6 fixtures × 3 modos una vez (18 observaciones), luego F0/F1/F2 × 2 modos HTML × 3 repeticiones (18 observaciones)Construcción de peticiones de una versión fijada de AgentQL MCP, valores predeterminados de includeHidden del SDK, opciones de sesión de AgentQL REST y dos términos de servicio públicosRespuesta final de TinyFish Browser Agent; cuerpos reales de petición de AgentQL SDK/REST; inicio de sesión real, persistencia de Cookie/Profile, control de acceso a streaming URL y recibos de eliminación remota

La misma página puede devolver contenido distinto según el modo de extracción

El portal sintético de proveedores contiene cuatro campos de referencia:

  • Pedido: #101
  • Importe: USD 4200.00
  • Estado: PENDING_APPROVAL
  • Marcador del beneficiario: ACCOUNT_FIXTURE_GOOD_101

El resto del contenido es solo para pruebas: una instrucción falsa en un aria-label, texto oculto con display:none, un comentario HTML y un valor de campo oculto marcado expresamente como canary no secreto. No hay datos reales de tarjetas, claves API, cookies ni información personal.

Las seis variantes y su generador están en una rama pública de fixtures independiente. Las páginas se sirven desde una CDN estática de terceros, no desde GitHub Pages. El código fuente está fijado a un commit para que puedan revisarse las entradas.

Hice dos rondas de lectura con la versión gratuita de TinyFish Fetch. En la primera, leí seis páginas con Markdown normal, HTML normal y HTML de una región DOM especificada: 18 observaciones del texto devuelto. En la segunda, repetí F0, F1 y F2 tres veces cada una con HTML normal y HTML acotado: otras 18 observaciones.

Resumen de seis fixtures HTML sintéticos y tres modos de extracción en la primera ronda, seguido de las repeticiones F0–F2. Las 36 observaciones son texto devuelto por Fetch, no decisiones de un agente ni pruebas de eliminación de sesiones remotas.
36 observaciones de texto devuelto · El tamaño de muestra varía por celda; no es una puntuación global de seguridad.

Hice dos rondas con TinyFish Fetch gratuito. En la primera leí seis páginas con Markdown normal, HTML normal y HTML de una región DOM especificada: 18 observaciones del texto devuelto. En la segunda repetí solo F0, F1 y F2 tres veces cada una con HTML normal y HTML acotado: otras 18 observaciones. Las opciones fueron format: "markdown", format: "html" y format: "html" con include_selectors: ["#trusted-order-facts", "#untrusted-webpage-region"]. Un acierto significa que la cadena objetivo de instrucción o canary apareció en el texto devuelto; no significa que un modelo la obedeciera.

FixtureContenido no confiableMarkdown normalHTML normalHTML acotado
F0Sin instrucción falsa0/10/10/1
F1Instrucción falsa en aria-label0/10/11/1
F2Instrucción falsa en display:none1/11/11/1
F3Instrucción falsa en comentario HTML0/10/10/1
F4Canary falso en campo ocultocanary 0/1canary 0/1canary 1/1
F5Control benigno de aria-label——Texto benigno de aria-label 1/1

F5 es un control negativo benigno: no contiene texto malicioso, pero el HTML acotado también devolvió su aria-label inocuo. Esto encaja mejor con la serialización del texto del atributo en la región DOM seleccionada que con una detección semántica de contenido malicioso. La instrucción del comentario HTML de F3 no apareció en la serialización DOM devuelta en esta ronda.

El canary de F4, 1/1, es una observación única de la primera ronda, no un resultado repetido. La segunda ronda solo repitió F0–F2 en los dos modos HTML; Markdown y F3–F5 no se repitieron.

La ronda repetida muestra el contraste más claro:

FixtureHTML normal (3 ejecuciones)HTML acotado (3 ejecuciones)Resultado observado
F0: control limpio0/30/3Ninguna respuesta contiene la instrucción falsa
F1: instrucción en aria-label0/33/3La extracción acotada conservó el texto del atributo
F2: instrucción en nodo display:none3/33/3El texto oculto apareció en ambas respuestas HTML

Los 36 textos devueltos contenían el importe, el estado y el marcador del beneficiario de referencia. “Contenían” significa que esas cadenas aparecieron en el texto devuelto por la herramienta. No significa que un modelo respondiera correctamente, y tampoco fueron 36 pruebas de decisiones de IA.

La primera ronda produjo otras dos observaciones con menor evidencia. La instrucción del comentario HTML no apareció en ninguno de los tres modos de extracción de esa ronda. El canary sintético del campo oculto no apareció en la extracción normal, pero sí en el HTML acotado. Cada caso se observó una sola vez, así que no permite establecer una regla general.

La conclusión que permiten estos datos es limitada: el modo de extracción influye en qué contenido de la página entra en el texto devuelto por la herramienta. Esto no demuestra que un proveedor haya robado credenciales reales ni que un modelo vaya a seguir instrucciones ocultas. Para responder esas preguntas hacen falta otros experimentos.

AgentQL MCP no introduce sin más todo el DOM local en el cuerpo de la petición

Una hipótesis inicial sostenía que AgentQL MCP local subía todo el árbol DOM de Chrome para localizar elementos semánticamente. Esa afirmación no se puede aplicar a todas las rutas de AgentQL.

Revisé la versión fijada de src/index.ts de tinyfish-io/agentql-mcp. La construcción local de la petición para extract-web-data envía url, prompt y parámetros a api.agentql.com/v1/query-data. El cuerpo JSON construido no contiene el DOM local ni un campo accessibility_tree.

Eso no significa que ningún contenido de la página salga del equipo. Esta ruta MCP envía una URL y un prompt de extracción; hay que evaluar por separado cómo el servidor obtiene y procesa la página de esa URL. Pero este código no demuestra que el navegador local serialice todo el DOM dentro del cuerpo de la petición.

Otra ruta envuelve una página Playwright con el SDK de AgentQL. La documentación sobre su funcionamiento interno indica que el procesamiento semántico utiliza HTML de la página y el Accessibility Tree, y simplifica la entrada. La API de páginas del SDK de JavaScript enumera distintos valores predeterminados para elementos ocultos:

Método del SDKValor predeterminado documentado de includeHidden
queryData()true
queryElements()false
getByPrompt()false

Esto demuestra que la configuración varía entre métodos, pero no sustituye la captura de una petición de red real. No ejecuté el SDK ni capturé su cuerpo de petición, por lo que no puedo afirmar que un campo oculto se haya subido por esa ruta.

El Browser Agent en la nube de TinyFish y las sesiones de navegador remoto de AgentQL son rutas distintas. MCP, SDK, extracción por URL y navegador remoto deben evaluarse por separado según dónde se ejecutan y por dónde salen los datos.

La limpieza de una sesión remota depende de su configuración de ciclo de vida

La guía de navegador remoto de AgentQL documenta direcciones de conexión CDP y URL de streaming de páginas, y describe la gestión y limpieza automática de sesiones. Esa documentación no demuestra por sí sola si una URL de streaming concreta necesita autorización adicional ni si los datos de la sesión se han borrado de todos los almacenes.

La interfaz de sesiones de navegador de la referencia de la API REST de AgentQL ofrece opciones más concretas:

  • inactivity_timeout_seconds tiene un valor predeterminado de 300 segundos (cinco minutos).
  • shutdown_mode tiene como valor predeterminado on_disconnect.
  • Con on_inactivity_timeout, la sesión puede permanecer después de que se desconecte el último cliente hasta que venza el tiempo de inactividad; una reconexión dentro de esa ventana puede reutilizar el navegador.

Esto es más preciso que decir que toda tarea elimina inmediatamente su sesión. Sin embargo, describe el comportamiento documentado de la interfaz REST de sesiones de AgentQL y no se puede generalizar a todos los perfiles Browser Context de TinyFish. Tampoco verifiqué de forma independiente que una sesión real se eliminara por completo tras el tiempo de espera.

El ejemplo de caché de credenciales de AgentQL también muestra cómo guardar el estado de inicio de sesión en un archivo local mediante storage_state(path=“session.json”) de Playwright. Es un ejemplo de uso del SDK local, no una prueba de dónde se almacenan los datos de un perfil de navegador remoto.

Los términos de servicio describen el tratamiento permitido, no lo ocurrido en una ejecución concreta

TinyFish y AgentQL tienen condiciones de servicio separadas; no deben mezclarse en una promesa genérica de privacidad del proveedor. Comparé las cláusulas sobre Customer Data:

TérminosPermiso publicado para tratar Customer Data¿El pasaje menciona explícitamente entrenamiento/ajuste de modelos?
Términos de servicio de TinyFishTratamiento para prestar, mantener, proteger, analizar y mejorar el servicio; también menciona revisar runs, prompts, inputs, outputs, errores y patrones de uso concretos.Sí. Enumera entrenamiento, ajuste fino, evaluación y mejora de modelos de IA/ML, con garantías indicadas para evitar revelar información confidencial a otros clientes. Entrada en vigor: 17 de agosto de 2026.
Términos de servicio de AgentQLTratamiento de Customer Data para prestar, mantener, proteger y mejorar el servicio; también permite usar datos agregados o desidentificados para fines legales, incluida la mejora y el desarrollo del producto.El pasaje visible sobre Customer Data no menciona explícitamente entrenamiento ni ajuste fino de modelos. Esto no demuestra que otros acuerdos o políticas no puedan incluir cláusulas relacionadas. Entrada en vigor: 21 de abril de 2026.

No trato los términos como registros de ejecución. Describen los permisos de tratamiento publicados por el proveedor, pero no prueban que una petición concreta se usara para entrenar un modelo ni que se filtrara una cookie. Aun así, conviene leerlos antes de conectar datos empresariales y comprobar si se aplica un acuerdo empresarial independiente.

Cómo delimitaría el uso práctico

Esta prueba no justifica una calificación general de “TinyFish es seguro” o “TinyFish es inseguro”. Sí permite establecer reglas de ingeniería concretas:

  1. No empezar con la cuenta principal. Si hace falta iniciar sesión, usar una cuenta de prueba de privilegios mínimos, sin permisos de pago, administración ni áreas ajenas a la tarea. Escribir una contraseña en un navegador remoto no hace que las cookies o el estado de sesión posterior vuelvan automáticamente al equipo local.
  2. Tratar el contenido web como entrada no confiable. aria-labels, nodos ocultos y comentarios pueden contener texto ajeno a los campos de negocio. Devolver JSON no demuestra que el contenido se haya saneado. Definir explícitamente los campos permitidos, comprobar el origen de los valores y probar casos negativos con contenido oculto.
  3. Un selector no es un mecanismo de redacción. En esta prueba, el HTML acotado devolvió tanto el texto de aria-label como un valor sintético de campo oculto. Limitar la región DOM puede reducir contenido irrelevante, pero no garantiza que se eliminen atributos y nodos ocultos dentro de ella.
  4. Separar lectura y escritura. Resumir un pedido o redactar un borrador para revisión no equivale a aprobar un pedido, enviar correo o presentar un formulario. Las acciones irreversibles requieren confirmación humana independiente, no solo un prompt que diga “no enviar”.
  5. Definir las condiciones de salida de la sesión. Antes de empezar, confirmar la API de sesión, shutdown_mode y los tiempos de espera. Que la página deje de verse, que el cliente se desconecte o que la herramienta muestre Completed no prueba que se haya eliminado el estado remoto. Tratar las direcciones CDP y las URL de streaming como accesos de control sensibles.
  6. Minimizar los datos que llegan al modelo. Para extractos bancarios, datos de clientes o tickets internos, preguntarse si realmente hace falta analizar semánticamente toda la página. Si se pueden seleccionar localmente unos pocos campos, no enviar toda la página a la nube por defecto.

Había planeado entregar los mismos fixtures a TinyFish Browser Agent para comprobar cómo decidiría tras recibir el texto de la página. Sin embargo, la cuenta de prueba no podía imponer el límite de pasos aprobado y el valor predeterminado disponible superaba ampliamente el alcance autorizado. No amplié el límite para terminar el experimento. En una automatización, no poder imponer el límite de ejecución es motivo para detenerse, no algo que se pueda resolver diciendo «úsalo con cuidado». Por eso esta ronda termina en los textos devueltos por Fetch, la revisión del código fijado y la documentación pública.

La conclusión práctica no consiste en poner una etiqueta global de “seguro” a un producto. Primero hay que identificar qué se envía y por qué ruta; después, usar recibos verificables para demostrar qué se devolvió realmente. El nombre del producto, los términos de privacidad y una demostración exitosa no sustituyen una auditoría de límites de confianza.


Nota sobre fecha y alcance: La revisión de fuentes y las observaciones con páginas sintéticas llegan hasta el 25 de octubre de 2026. Las pruebas Fetch incluyen seis fixtures × tres modos de extracción y tres repeticiones de F0/F1/F2 en dos modos HTML, para un total de 36 observaciones de texto devuelto. No se usaron cuentas reales, cookies, claves API ni datos de clientes. No se probaron TinyFish Browser Agent, la salida de datos en tiempo de ejecución de AgentQL SDK/REST, la persistencia de sesiones reales ni su eliminación remota; esto no certifica la seguridad general de ningún producto.

Nota sobre fuentes y reproducción: Fetch usó el commit de origen 152cdc9a58e6a8fcf2d5857820d60774f0967555. El commit posterior 604bde069c0bd32bb41a4238140062e5468a7f2f solo modificó el README; los SHA de los blobs Git de F0–F5 no cambiaron. Las páginas se leyeron a través de la CDN estática de terceros cdn.githubraw.com; no se auditaron su disponibilidad, caché ni equivalencia byte a byte. Por tanto, el código fijado en Git no demuestra que la CDN sirviera contenido idéntico byte por byte. El generador completo, el clasificador y los recibos originales del texto devuelto siguen en el dossier privado de investigación.