반례 검토 그림: F0은 일반 HTML과 지정 영역 HTML 모두 0/3, F1의 aria-label 지시는 지정 영역 HTML에서 3/3, F2의 display:none 노드는 두 모드 모두 3/3이다. Fetch 반환 텍스트만 관찰했으며 Agent의 판단이나 원격 세션 삭제를 검증한 것은 아니다.
반례 프로브 · Fetch 반환 텍스트는 Agent의 지시 준수 테스트가 아니다. 픽스처 문구는 중국어 원문을 번역한 것입니다.

AI Agent가 빠르게 발전하면서 Meta Muse, ChatGPT Dots, Claude Duet 같은 새로운 도구도 써 보기 시작했다. 브라우저를 제어하고, 관리 화면에 로그인하고, 작업 흐름을 자동으로 끝내는 일은 몇 단계면 되는 것처럼 보인다. 하지만 화면이 저절로 이동하는 모습을 볼 때마다 조금 덜 멋진 질문이 먼저 떠오른다. 작업이 끝난 뒤 클라우드에 맡긴 계정 데이터는 어디로 갔을까? 로그인 상태는 언제 끝날까? 도구가 그 상태를 탈취하거나 페이지에 주문 사실을 바꾸려는 숨은 문구가 있다면 누가 책임질까? 이런 질문은 클라우드 Agent가 위험하다고 미리 단정하기 위한 것이 아니라 실제 업무를 맡기기 전에 신뢰 경계를 확인하려는 것이다.

제품 데모는 흐름이 작동한다는 사실은 보여 주지만 이런 질문에 깊이 답하기는 어렵다. 이번에는 TinyFish를 선택해 문제를 작게 나눴다. 가상의 주문만 포함한 HTML 페이지 여섯 개에서 TinyFish Fetch가 실제로 무엇을 반환하는지 확인하고, 고정 버전 AgentQL MCP 소스, SDK 문서, 원격 브라우저 세션 문서, 두 서비스의 별도 약관을 검토했다.

먼저 범위를 분명히 한다. 이번에 관찰한 것은 추출 모드에 따라 도구가 반환하는 텍스트가 달라진다는 점이다. 그 텍스트를 Agent에 전달하지 않았으므로 Agent가 가짜 지시를 따르는지는 판단할 수 없다. 실제 계정, 쿠키, 원격 세션, 원격 데이터 삭제는 이번 테스트 범위가 아니다.

페이지를 가져오는 일, 내용을 모델에 전달하는 일, 모델이 다음 행동을 결정하는 일, 계정 로그인 상태를 원격에 유지하는 일은 서로 다른 계층이다. Fetch만 사용해도 사람 눈에 보이지 않는 텍스트가 반환될 수 있지만 모델이 반드시 따르는 것은 아니다. 페이지 내용을 바탕으로 Agent가 클릭하게 하거나 로그인 세션을 클라우드에 넘기는 것은 별도의 위험 관문이며 이번에는 테스트하지 않았다.

증거 범위

실측정적 검토테스트하지 않음
TinyFish Fetch 반환 텍스트: 픽스처 6개 × 모드 3개 각 1회(18건), 이후 F0/F1/F2 × HTML 모드 2개 × 각 3회 반복(18건)고정 버전 AgentQL MCP 요청 구성, SDK includeHidden 기본값, AgentQL REST 세션 옵션, 공개 서비스 약관 2종TinyFish Browser Agent 최종 답변, 실제 AgentQL SDK/REST 요청 본문, 실제 로그인·Cookie/Profile 보존, streaming URL 접근 제어, 원격 삭제 증거

같은 페이지라도 추출 모드에 따라 반환 내용이 달라진다

합성 공급업체 포털에는 기준 필드 네 개가 있다.

  • 주문: #101
  • 금액: USD 4200.00
  • 상태: PENDING_APPROVAL
  • 수취인 마커: ACCOUNT_FIXTURE_GOOD_101

나머지는 테스트 전용 콘텐츠다. aria-label 안의 가짜 지시, display:none으로 숨긴 텍스트, HTML 주석, 비밀이 아니라고 명시한 숨겨진 필드 canary를 넣었다. 실제 카드 정보, API 키, 쿠키, 개인정보는 포함하지 않았다.

여섯 변형과 생성 코드는 독립 공개 픽스처 브랜치에 있다. 페이지는 GitHub Pages가 아닌 제3자 정적 CDN에서 제공하며, 입력을 검토할 수 있도록 소스를 특정 commit에 고정했다.

무료 TinyFish Fetch로 두 차례 읽기를 수행했다. 첫 번째 라운드에서는 여섯 페이지를 일반 Markdown, 일반 HTML, 지정 DOM 영역 HTML로 각각 읽어 반환 텍스트 18건을 얻었다. 두 번째 라운드에서는 F0, F1, F2만 골라 일반 HTML과 지정 영역 HTML을 각각 세 번 반복해 18건을 더 얻었다.

합성 HTML 픽스처 여섯 개의 첫 라운드 추출 모드 비교와 F0–F2 반복 결과. 36건은 Fetch 반환 텍스트이며 Agent 판단이나 원격 세션 삭제의 증거가 아니다.
반환 텍스트 36건 · 테스트 셀마다 표본 수가 다르므로 전체 보안 점수로 해석하면 안 된다.

무료 TinyFish Fetch로 두 차례 읽기를 진행했다. 첫 번째는 HTML 페이지 여섯 개를 일반 Markdown, 일반 HTML, 지정 DOM 영역 HTML로 각각 한 번씩 읽어 반환 텍스트 18건을 얻었다. 두 번째는 F0, F1, F2만 일반 HTML과 지정 영역 HTML에서 각각 세 번 반복해 18건을 더 얻었다. 설정은 format: "markdown", format: "html", 그리고 format: "html"과 include_selectors: ["#trusted-order-facts", "#untrusted-webpage-region"] 조합이었다. 적중은 대상 가짜 지시나 canary 문자열이 반환 텍스트에 나타났다는 뜻이지 모델이 지시를 따랐다는 뜻이 아니다.

픽스처신뢰할 수 없는 내용일반 Markdown일반 HTML지정 영역 HTML
F0가짜 지시 없음0/10/10/1
F1aria-label 안의 가짜 지시0/10/11/1
F2display:none 가짜 지시1/11/11/1
F3HTML 주석 가짜 지시0/10/10/1
F4숨김 필드의 가짜 canarycanary 0/1canary 0/1canary 1/1
F5무해한 aria-label 대조군——무해한 aria-label 텍스트 1/1

F5는 무해한 음성 대조군이다. 악의적인 문구가 없는데도 지정 영역 HTML은 무해한 aria-label을 반환했다. 이는 악의적인 의미를 감지했다기보다 선택한 DOM 영역의 속성 텍스트가 출력에 직렬화됐다는 설명에 더 잘 맞는다. F3의 HTML 주석 지시는 이번 라운드의 반환 DOM 직렬화에 나타나지 않았다.

F4 canary의 1/1은 첫 라운드에서 한 번 관찰한 결과이며 반복 결과가 아니다. 두 번째 라운드는 F0–F2의 두 HTML 모드만 반복했고 Markdown 및 F3–F5는 반복하지 않았다.

반복 테스트에서 가장 분명한 차이는 다음과 같다.

픽스처일반 HTML(3회)지정 영역 HTML(3회)관찰 결과
F0: 깨끗한 대조군0/30/3두 응답 모두 가짜 지시 텍스트 없음
F1: aria-label 안의 지시0/33/3지정 영역 추출이 속성 텍스트를 보존
F2: display:none 노드 안의 지시3/33/3숨겨진 노드 텍스트가 두 HTML 응답에 모두 등장

반환 텍스트 36건 모두 기준 주문 금액, 상태, 수취인 마커를 포함했다. 여기서 “포함”은 해당 문자열이 도구 반환 텍스트에 나타났다는 뜻이다. 모델이 정답을 냈다는 의미도 아니며, 36회의 AI 판단 테스트도 아니다.

첫 라운드에서는 표본이 더 적은 관찰도 두 가지 있었다. HTML 주석의 가짜 지시는 해당 라운드의 세 추출 모드 어디에도 나타나지 않았다. 합성 숨겨진 필드 canary는 일반 추출에는 없었지만 지정 영역 HTML에는 나타났다. 각각 한 번만 관찰했으므로 일반적인 규칙으로 확대할 수 없다.

이 테스트가 뒷받침하는 결론은 제한적이다. 추출 모드에 따라 도구 반환 텍스트에 포함되는 페이지 콘텐츠가 달라진다. 공급업체가 실제 자격 증명을 훔쳤다는 증거도, 모델이 숨겨진 지시를 따른다는 증거도 아니다. 그런 질문에는 별도의 실험이 필요하다.

AgentQL MCP가 로컬 DOM 전체를 요청 본문에 넣는 것은 아니다

처음에는 로컬 AgentQL MCP가 의미 기반 요소 탐색을 위해 로컬 Chrome의 전체 DOM 트리를 클라우드로 업로드한다는 가정이 있었다. 하지만 이 설명을 모든 AgentQL 경로에 적용할 수는 없다.

고정 버전의 tinyfish-io/agentql-mcp src/index.ts를 살펴봤다. extract-web-data의 로컬 요청 구성은 url, prompt, 매개변수를 api.agentql.com/v1/query-data로 전송한다. 구성된 JSON 요청 본문에는 로컬 DOM이나 accessibility_tree 필드가 없다.

그렇다고 페이지 콘텐츠가 외부로 전혀 나가지 않는다는 뜻은 아니다. 이 MCP 경로는 URL과 추출 프롬프트를 보내며, 서버가 해당 URL의 페이지를 어떻게 가져오고 처리하는지는 별도로 살펴봐야 한다. 다만 이 소스는 로컬 브라우저가 DOM 전체를 직렬화해 요청 본문에 넣는다는 증거가 아니다.

다른 경로에서는 AgentQL SDK로 Playwright 페이지를 감싼다. AgentQL의 내부 동작 문서는 의미 처리에 페이지 HTML과 Accessibility Tree를 사용하고 입력을 단순화한다고 설명한다. JavaScript SDK 페이지 API에는 숨겨진 요소에 대한 메서드별 기본값이 나와 있다.

SDK 메서드문서상 includeHidden 기본값
queryData()true
queryElements()false
getByPrompt()false

이는 메서드마다 설정이 다르다는 뜻이지 실제 네트워크 요청 캡처를 대신하지는 않는다. SDK를 실행하거나 요청 본문을 캡처하지 않았으므로, 숨겨진 필드가 SDK 경로로 업로드됐다고 주장할 수 없다.

TinyFish 클라우드 Browser Agent와 AgentQL 원격 브라우저 세션도 별도의 경로다. MCP, SDK, URL 추출, 원격 브라우저는 실행 위치와 데이터 유출 경로를 구분해 평가해야 한다.

원격 세션 정리는 수명주기 설정에 달려 있다

AgentQL의 원격 브라우저 가이드는 CDP 연결 주소와 페이지 streaming URL을 설명하고 자동 세션 관리 및 정리를 소개한다. 하지만 문서만으로 특정 streaming URL에 추가 인증이 필요한지, 모든 저장소에서 세션 데이터가 삭제됐는지는 알 수 없다.

AgentQL REST API 참조의 브라우저 세션 인터페이스에는 더 구체적인 설정이 있다.

  • inactivity_timeout_seconds 기본값은 300초(5분)다.
  • shutdown_mode 기본값은 on_disconnect다.
  • on_inactivity_timeout을 사용하면 마지막 클라이언트가 연결을 끊은 뒤에도 유휴 시간 제한이 끝날 때까지 세션이 남을 수 있으며, 그 전에 재연결하면 기존 브라우저를 재사용할 수 있다.

이는 “작업이 끝나면 무조건 즉시 삭제된다”는 말보다 구체적이다. 하지만 AgentQL REST 세션 인터페이스의 문서상 동작이며 모든 TinyFish Browser Context Profile에 일반화할 수 없다. 실제 세션이 시간 초과 뒤 완전히 삭제됐는지 독립적으로 확인한 것도 아니다.

AgentQL의 자격 증명 캐시 예제는 Playwright의 storage_state(path=“session.json”) 로 로그인 상태를 로컬 파일에 저장하는 방법도 보여준다. 이는 로컬 SDK의 한 사용 방식일 뿐 원격 Browser Profile의 데이터 저장 위치를 증명하지 않는다.

서비스 약관은 허용된 처리를 설명할 뿐, 특정 실행에서 실제로 일어난 일을 증명하지 않는다

TinyFish와 AgentQL의 서비스 약관은 서로 별개다. 두 문서를 모호한 하나의 “공급업체 개인정보 약속”으로 합쳐서는 안 된다. Customer Data 조항을 나란히 비교했다.

약관공개된 Customer Data 처리 허가이 조항에 모델 학습/미세조정이 명시돼 있는가
TinyFish 서비스 약관서비스 제공·유지·보안·분석·개선을 위한 처리와 특정 runs, prompts, inputs, outputs, errors 및 사용 패턴 검토를 언급한다.그렇다. AI/ML 모델 학습, 미세조정, 평가, 개선을 명시하며 다른 고객에게 기밀 정보가 공개되지 않도록 하는 보호 문구도 포함한다. 발효일: 2026년 8월 17일.
AgentQL 서비스 약관서비스 제공·유지·보안·개선을 위한 Customer Data 처리와 제품 개선·개발 등 합법적 목적의 집계 또는 비식별 데이터 사용을 허용한다.현재 확인 가능한 Customer Data 조항에는 모델 학습이나 미세조정이 명시돼 있지 않다. 다른 계약이나 정책에도 관련 조항이 없다는 뜻은 아니다. 발효일: 2026년 4월 21일.

서비스 약관을 실행 로그처럼 취급하지 않는다. 약관은 공급자가 공개한 데이터 처리 권한을 설명할 뿐 특정 요청이 실제 학습에 사용됐거나 쿠키가 유출됐다는 증거가 아니다. 그래도 업무 데이터를 연결하기 전 읽어 볼 가치가 있으며 별도 기업 계약이 적용되는지 확인해야 한다.

실제 사용 경계는 이렇게 정하겠다

이 테스트만으로 TinyFish 전체에 “안전” 또는 “위험”이라는 평가를 내릴 수는 없다. 하지만 다음과 같은 실무 규칙은 도출할 수 있다.

  1. 주 계정으로 시험하지 않는다. 로그인이 필요하면 결제·관리자·무관한 업무 권한을 제거한 별도 저권한 테스트 계정을 사용한다. 원격 브라우저에 비밀번호를 입력했다고 이후의 쿠키나 세션 상태가 자동으로 로컬에 남는 것은 아니다.
  2. 웹페이지 콘텐츠를 신뢰할 수 없는 입력으로 취급한다. aria-label, 숨겨진 노드, 주석에는 업무 필드와 무관한 텍스트가 들어갈 수 있다. JSON 반환은 정화의 증거가 아니다. 허용 필드를 명시하고 값의 출처를 확인하며 숨겨진 콘텐츠에 대한 부정 테스트를 수행한다.
  3. 선택자는 마스킹 기능이 아니다. 이번 지정 영역 HTML은 aria-label 텍스트와 합성 숨겨진 필드 값을 모두 반환했다. DOM 범위를 좁히면 불필요한 내용을 줄일 수 있지만 그 안의 속성과 숨겨진 노드가 자동 제거된다고 가정해서는 안 된다.
  4. 읽기와 쓰기를 분리한다. 주문 정리나 검토 초안 작성과 주문 승인, 이메일 발송, 양식 제출은 서로 다른 권한이다. 되돌릴 수 없는 작업에는 독립적인 사람의 확인이 필요하며 “제출하지 말라”는 프롬프트만으로는 충분하지 않다.
  5. 세션 종료 조건을 명시한다. 작업 전에 세션 API, shutdown_mode, 시간 제한을 확인한다. 페이지가 보이지 않는 것, 클라이언트 연결 종료, 도구의 Completed 상태는 원격 상태가 삭제됐다는 증거가 아니다. CDP 주소와 streaming URL은 민감한 제어 지점으로 취급한다.
  6. 모델에 보내는 데이터를 최소화한다. 명세서, 고객 기록, 내부 티켓을 처리할 때 전체 페이지의 의미 분석이 정말 필요한지 먼저 묻는다. 로컬에서 소수 필드만 선택할 수 있다면 기본적으로 페이지 전체를 클라우드로 보내지 않는다.

원래는 같은 픽스처를 TinyFish Browser Agent에 전달해 페이지 텍스트를 받은 뒤 어떤 판단을 하는지 확인하려 했다. 하지만 테스트 계정은 승인된 단계 수 제한을 강제할 수 없었고, 사용 가능한 기본값은 이번 실험의 허용 범위를 훨씬 넘었다. 실험을 끝내려고 제한을 완화하지 않았다. 자동화에서 실행 경계를 강제할 수 없다는 사실 자체가 중단 사유이며 “조심해서 사용하라”는 말로 넘길 문제가 아니다. 이번 라운드는 Fetch 반환 텍스트, 고정 버전 소스, 공개 문서 검토에서 멈췄다.

실용적인 결론은 제품에 일괄적으로 “안전”이라는 꼬리표를 붙이는 것이 아니다. 무엇을 어떤 경로로 보내는지 먼저 확인하고, 실제로 무엇이 반환됐는지 재검토 가능한 증거로 남겨야 한다. 제품명, 개인정보 약관, 한 번의 성공적인 시연은 신뢰 경계 감사를 대신하지 못한다.


참고 / 시간 및 범위: 소스 검토와 합성 페이지 테스트 기록은 2026년 10월 25일까지다. Fetch 테스트는 픽스처 6개 × 추출 모드 3개와 F0/F1/F2를 두 HTML 모드에서 각각 3회 반복한 결과로 총 36건의 반환 텍스트를 포함한다. 실제 계정, 쿠키, API 키, 고객 데이터는 사용하지 않았다. TinyFish Browser Agent, AgentQL SDK/REST 런타임 데이터 전송, 실제 세션 보존, 원격 삭제는 테스트하지 않았으며 제품 전체의 보안 인증이 아니다.

소스 및 재현 참고: Fetch는 소스 커밋 152cdc9a58e6a8fcf2d5857820d60774f0967555를 사용했다. 후속 커밋 604bde069c0bd32bb41a4238140062e5468a7f2f는 README만 변경했고 F0–F5의 Git blob SHA는 바뀌지 않았다. 페이지는 제3자 정적 CDN cdn.githubraw.com을 통해 읽었으며 가용성, 캐시, 바이트 동일성은 감사하지 않았다. 따라서 고정 Git 소스가 CDN에서 바이트 단위로 동일한 콘텐츠를 제공했다는 증거는 아니다. 전체 생성기, 판정 스크립트, 원본 반환 텍스트는 비공개 연구 자료에 보관돼 있다.