COMMIT-PINNED · STATIC-ONLY

agent-browser

브라우저 명령의 편의와 권한 경계는 같은 문제가 아니다.

분석 범위

공개 저장소 vercel-labs/agent-browser의 독립 정적 분석이다. 프로젝트 공식 문서나 보증이 아니다.

main · SHA-1 8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2
root tree 149e572fba2ab3c60a404bf0a9d6310ed529cc57
capture 679f00e57079427f8e039e6d3fb9b8df · 시작 2026-09-11 07:07 UTC

전체 트리 612개 항목을 확인하고 16개 파일, 12,472줄을 캡처했다. 파일 내용을 캡처했다는 사실은 모든 경로를 감사했다는 뜻이 아니다. 실행·설치·테스트·벤치마크는 하지 않았다.

읽기 전에

핵심 질문: 브라우저 명령을 짧게 호출하는 것과 그 명령을 안전하게 제한하는 것은 어디에서 갈리는가?

이 도구는 자연어를 스스로 판단하는 모델이 아니라 외부 호출자가 브라우저를 제어할 수 있게 하는 명령 계층으로 읽어야 한다. 명령은 로컬 daemon에 JSON으로 전달된다. 승인 보류·실제 완료·실패는 별개의 상태다.

  • 10분: 채택 판단 → 확인 보류의 의미 → 정책 분기.
  • 30분: CLI/daemon 경로 → 설치·자격증명 → CI 샘플.
  • 기여자: main/connection 다음 actions 구현과 관련 테스트를 추가로 읽어야 한다. 이번 캡처는 actions까지 닫히지 않았다.

점검 질문: exit 0이면 작업이 끝났는가? 빈 allow 목록은 차단인가? 테스트 파일이 있으면 현재 SHA도 통과했는가?

채택 판단

Evidence trust C

Implementation confidence low

Runtime confidence unknown

Maintenance coverage medium

Security / privacy confidence unknown

격리된 시험 환경의 후보로 볼 수 있지만, 권한 제한을 전제로 운영에 투입하기에는 확인되지 않은 경계가 남아 있다.

Evidence trust C · Runtime confidence unknown. 실제 action dispatcher와 모든 outbound 경로를 읽지 않았으며, 캡처 SHA의 historical CI는 실패 상태다. 별점이나 출시 빈도가 이 공백을 메우지는 않는다.

적합: 외부 에이전트의 브라우저 조작 인터페이스를 검토하려는 개발자. 부적합: 이 분석만으로 운영 계정·고권한 자격증명·결제·외부 발신 자동화의 안전성을 승인하려는 경우.

코드에서 확인한 동작

verified는 위 코드 분기를 뜻한다. 제품 전체 보안 강제는 unknown이다. actions 모듈 미판독 때문에 helper의 존재만으로 종단 강제를 주장하지 않는다.

package.json의 bin은 ./bin/agent-browser.js다. 래퍼는 OS/CPU와 Linux musl 여부에 따라 파일명을 정하고, 파일이 없으면 오류로 끝내며, Unix에서 실행 비트를 복구한 뒤 원래 CLI 인자를 그대로 spawn한다. Windows ARM64는 source-built ARM64 파일이 있으면 우선하고 없으면 x64 에뮬레이션 파일로 간다.

package.json#L1-L34 bin/agent-browser.js#L19-L75 bin/agent-browser.js#L78-L126

npm과 Cargo는 0.37.1을 선언한다. npm은 Node >=24 및 pnpm >=11을 선언하며 runtime dependency 목록 없이 devDependencies 빈 객체다. Rust manifest에는 Tokio, WebSocket, reqwest/rustls, aes-gcm, image, zip 등이 있다. 이는 네이티브 구현의 재료를 보여줄 뿐 모든 기능이 Rust-only라는 동작 증명이나 의존성 취약점 검증은 아니다.

package.json#L1-L10 package.json#L45-L54 cli/Cargo.toml#L1-L45

관찰은 핸들을 만든다

페이지를 통째로 이해하는 모델이 아니라 브라우저가 내놓은 접근성 노드에 CLI용 핸들을 붙이는 관찰기다. 관찰 → 현재 출력의 ref 선택 → 행동 → 상태가 바뀌면 다시 관찰이 기본 루프다. e2라는 번호 자체에는 Submit 같은 영구 의미가 없다.

DOM.enable 및 Accessibility.enable → 선택적 CSS selector를 Runtime.evaluate로 찾고 DOM.describeNode로 하위 backendNodeId 집합 수집 → Accessibility.getFullAXTree

cli/src/native/snapshot.rs#L225-L328

AX 노드에서 역할·이름·상태·값·backend node ID를 추출하고 트리를 만든다. ignored 노드와 InlineTextBox를 비우고 연속 StaticText를 합치는 등 이미 가공된 표현이다.

cli/src/native/snapshot.rs#L950-L1081

버튼 같은 interactive role뿐 아니라 이름 있는 heading·article 등 content role과 cursor-interactive 노드에도 ref를 배정한다. 중복 role:name에 nth를 붙이고 eN → backend node ID, role, name, nth, frame_id를 RefMap에 저장한다. 번호는 RefMap의 next_ref_num에서 시작해 증가한다.

cli/src/native/snapshot.rs#L365-L438

출력에는 역할·정규화된 이름·상태·ref·선택적 URL·값을 싣는다. interactive 모드는 실제 클릭 가능성 검사가 아니라 has_ref가 없는 노드를 생략하는 방식이다.

cli/src/native/snapshot.rs#L1084-L1213

명령이 이동하는 경로

  1. argv → CLI 파싱·JSON 명령. cli/src/main.rs:1535-1552
  2. ensure_daemon → 로컬 daemon 생성/재사용. cli/src/connection.rs:867-915
  3. send_command → 한 줄 JSON IPC. cli/src/connection.rs:1013-1042
  4. handle_connection → mutex → execute_command. cli/src/native/daemon.rs:552-565
  5. 미확인 연결: execute_command 내부의 정책·승인·실제 브라우저 호출과 결과.
  6. 응답 출력. 확인 UI가 켜진 비TTY 요청은 승인되지 않고 deny 후 exit 1. cli/src/main.rs:368-415

전송 재시도는 transient 오류에서 같은 JSON을 다시 보낸다. 응답만 유실됐을 때 중복 부작용을 방지하는지는 dispatcher의 중복 제거를 더 읽어야 한다. cli/src/connection.rs:1013-1065

설치와 첫 성공의 조건

commands — not run. 다음은 README의 명령 인용이다. 실행 권고나 실행 영수증이 아니다. 특히 pnpm build는 이 커밋의 package scripts에 없어 그대로 성공할 절차라고 제시하지 않는다.

npm install -g agent-browser

npm install -g agent-browser

not run — README 원문 명령 인용이며 실행 권고나 승인 요청이 아니다 · 패키지 다운로드·lifecycle 실행·네이티브 바이너리 다운로드·전역 진입점 변경 가능. 버전 미고정이므로 이번 소스 커밋과 동일한 결과를 보장하지 않는다.

README.md#L13-L16

agent-browser install

agent-browser install

not run — README 원문 명령 인용 · README는 Chrome for Testing 다운로드라고 설명한다. 실제 download 구현은 이 파일 묶음에서 검토하지 않았다.

README.md#L13-L16

agent-browser upgrade

agent-browser upgrade

not run — README 원문 명령 인용 · README상 설치 방식에 따라 최신 버전으로 변경하는 명령이다. 읽기 전용 확인 명령이 아니며 실제 실행 인자·공급원 검증은 미확인이다.

README.md#L67-L75

pnpm build

pnpm build

not run — 실행 가능성이 확인되지 않은 README 원문 인용 · 루트 package.json에 해당 script가 없어 검증된 소스 빌드 절차로 제시하지 않는다.

README.md#L47-L55

agent-browser snapshot -i

agent-browser snapshot -i

not run — README 원문 명령 인용 · 스냅샷 구현은 CDP 호출과 페이지 JS 실행 및 임시 DOM 속성 변경을 포함한다. 새 프로세스/브라우저 생성 여부는 호출부에 달려 있다.

README.md#L960-L967

agent-browser click @e2

agent-browser click @e2

not run — README 원문 명령 인용 · @e2는 해당 관찰 결과에서 고른 핸들이어야 한다. 예시 번호를 실제 페이지에 재사용하면 안 된다. 클릭은 외부 상태 변경을 유발할 수 있다.

README.md#L1216-L1232

정상 성공 신호는 관찰 결과에 유효한 ref가 나타나고 실제 의도한 페이지 상태가 바뀌는 것이다. 이번 분석에서는 실행으로 확인하지 않았다. 전체 uninstall/잔존 파일 cleanup 경로도 검증하지 않았다.

역할별 읽기 순서

  • 사용자: README의 기대 동작과 CLI 응답 형식을 함께 확인.
  • 운영자: connection → daemon → network. 재시도·세션·요청 제한 경계를 우선.
  • 기여자: main → actions → 브라우저/CDP → 해당 e2e. actions 이후는 이번 초안의 검증 범위 밖.
  • 보안 검토자: policy → 실제 호출자 → auth → outbound/stream. helper 단독 판독으로 닫지 않는다.

출시 빈도와 현재 CI는 따로 본다

2026-09-11 수집한 최근 10개 published release 샘플의 최신은 v0.37.1(2026-09-08)이다. 샘플 내 출시 간격 중앙값은 약 4.57일이며 범위는 0.63–14.20일이다. 태그 10개는 별도 수집했고 생성 시각이 없어 태그 빈도는 계산하지 않았다.

분석 SHA의 CI run은 failure다. Windows Rust의 Run Rust tests, Native E2E의 Run e2e tests가 실패했다. 로그 미수집으로 원인은 unknown이다.

최근 업데이트 순 Issues API 20행 중 PR 14행을 제외한 이슈는 6개다. 이 중 5개 댓글 샘플에서 작성자가 아닌 사람의 응답을 확인한 3건의 첫 응답 중앙값은 64.48시간이다. 응답 없는 2건을 0시간으로 계산하지 않았다. 작은 편의 표본이며 전체 프로젝트 응답성 수치가 아니다.

CI 설정은 PR 이벤트에서 cross-platform/e2e를 제외한다. .github/workflows/ci.yml:140-175

보안·개인정보·공급망

도메인 helper의 빈 목록은 무제한 허용이다. hostname 기반 매칭과 OS 방화벽은 다른 경계다. 이 helper로 DNS·모든 context·모든 outbound 경로를 보장할 수 없다. cli/src/native/network.rs:84-134

공개 advisory 응답은 0건이었지만 취약점이 없다는 뜻은 아니다. branch protection은 비인증 요청에서 HTTP 401을 반환해 unknown이다. 비공개 보안 경보는 확인하지 않았다.

검사한 workflow의 외부 action은 full SHA가 아닌 v4/stable 등의 가변 태그를 사용한다. npm provenance 발행은 설정되어 있으나 실제 증명 검증은 하지 않았다. .github/workflows/release.yml:324-348

설치는 다운로드 이상의 권한이다

npm lifecycle postinstall은 현재 패키지 version과 플랫폼명으로 https://github.com/vercel-labs/agent-browser/releases/download/v${version}/${binaryName}를 만든다. 파일이 없으면 Node https.get으로 다운로드하고 301/302 Location을 재귀적으로 따른다. 수집 커밋을 고정해 읽었다는 것과 사용자가 npm 설치 시 받는 릴리스 실행 파일의 소스 동일성은 별개의 문제다.

package.json#L22-L34 scripts/postinstall.js#L34-L83 scripts/postinstall.js#L111-L163

이 postinstall 다운로드 경로에는 checksum·서명·다운로드 크기 검증, redirect host allowlist, 명시적 timeout·redirect 횟수 제한이 없다. 이미 있는 파일도 존재 여부만으로 ready 처리한다. 이는 코드상 검증 부재이지 실제 공급망 변조가 발생했다는 뜻은 아니다.

scripts/postinstall.js#L54-L83 scripts/postinstall.js#L111-L126

createWriteStream은 HTTP 상태를 알기 전에 목적지에 열리며, non-200 분기는 reject만 한다. 다운로드 실패는 로그 후 진행하고 종료코드 실패를 설정하지 않는다. 따라서 설치 단계가 끝나더라도 사용 가능한 바이너리가 있다고 단정할 수 없다. 다음 실행에서 남은 파일을 존재만으로 ready 처리할 위험은 정적 경로로 확인되지만 실제 재현은 하지 않았다.

scripts/postinstall.js#L54-L79 scripts/postinstall.js#L111-L126 scripts/postinstall.js#L140-L163 scripts/postinstall.js#L321

postinstall은 Unix에서 chmod 0755를 적용하며 npm prefix -g로 찾은 agent-browser symlink를 삭제·재생성할 수 있다. symlink의 기존 목적지가 이 설치본인지 검증하는 조건은 없다. Windows는 예상 바이너리가 존재할 때 .cmd/.ps1 shim을 덮어쓴다. 즉 설치 권한은 전역 실행 진입점 변경까지 포함한다.

scripts/postinstall.js#L239-L270 scripts/postinstall.js#L278-L318

이 postinstall은 Chrome을 직접 다운로드하지 않고 로컬 Chrome 존재를 확인한 뒤 필요하면 agent-browser install을 안내한다. .install-method에는 npm/pnpm/yarn/bun을 기록해 upgrade 경로에 전달하려는 의도가 보인다. 실제 upgrade 실행 명령·Chrome 다운로드 호스트/검증·Linux 시스템 패키지 설치는 지정된 구현 파일 밖이라 미확인이다.

scripts/postinstall.js#L86-L109 scripts/postinstall.js#L166-L221 README.md#L57-L81

암호화와 계정 격리는 다르다

AuthProfile은 URL·username·password·선택적 폼 selector를 포함한다. 새 저장은 프로필 전체를 JSON 직렬화해 AES-256-GCM으로 암호화하고 무작위 12바이트 IV와 16바이트 인증 태그를 base64 JSON envelope로 저장한다. 기본 위치는 ~/.agent-browser/auth/<name>.json이며 home 디렉터리를 찾지 못하면 temp/agent-browser/auth로 간다.

cli/src/native/auth.rs#L9-L55 cli/src/native/auth.rs#L151-L181 cli/src/native/auth.rs#L236-L253

키는 AGENT_BROWSER_ENCRYPTION_KEY의 64자리 hex를 우선하며 없으면 ~/.agent-browser/.encryption-key를 읽는다. 자동 생성 키는 같은 사용자 디렉터리에 평문 hex로 저장한다. Unix dir 0700/file 0600 설정은 시도하지만 실패를 무시한다. Windows 전용 ACL 설정은 이 파일에 없다. 암호문과 키를 함께 읽을 수 있는 계정/백업/침해자에 대한 격리는 이 설계만으로 제공되지 않는다.

cli/src/native/auth.rs#L57-L148 cli/src/native/auth.rs#L236-L253

중요 정적 결함: ensure_encryption_key는 get_encryption_key의 모든 오류를 키 없음과 동일하게 처리한다. 잘못된 환경 키·손상된 키 파일·키 읽기 오류도 새 키 생성 및 .encryption-key 쓰기로 이어진다. 잘못된 환경변수가 계속 있으면 복호화는 다시 그 환경변수를 우선하므로 새 저장본을 읽지 못하고, 기존 키 파일이 덮이면 예전 프로필도 복호화 불능이 될 수 있다. 오류 종류를 분리한 fail-closed 처리가 필요하다는 판단이며 실행 재현은 하지 않았다.

cli/src/native/auth.rs#L85-L112 cli/src/native/auth.rs#L114-L148 cli/src/native/auth.rs#L197-L224

credentials_get와 auth_show 출력은 password를 생략하지만 내부 credentials_get_full은 평문 AuthProfile을 반환한다. decrypt_profile에는 평문 JSON 프로필을 허용하는 fallback도 있다. 따라서 새 저장은 암호화됨과 어떤 입력/실행 경로에서도 비밀번호가 LLM에 절대 노출되지 않음은 다른 주장이다. 후자는 login/출력/스크린샷/로그 소비자를 추가로 확인해야 한다.

cli/src/native/auth.rs#L197-L234 cli/src/native/auth.rs#L312-L324 cli/src/native/auth.rs#L374-L387

라이선스와 채택 조건

Apache-2.0; LICENSE의 저작권 표시는 Copyright 2025 Vercel Inc.

조건을 지키는 사용·수정·상업적 배포가 가능한 허용적 라이선스다. 법률 자문이나 개별 배포물의 권리 완결성 보증은 아니다.

저작권 허락은 복제·파생물 작성·공개·재라이선스·배포를 포함한다. 특허 허락은 기여자가 허락할 수 있는 관련 특허 청구항으로 한정되며 해당 작업에 대한 특허소송을 제기하면 종료될 수 있다.

LICENSE#L66-L87

재배포 시 라이선스 사본 제공, 수정 파일의 눈에 띄는 변경 표시, 관련 저작권·특허·상표·귀속 고지 유지가 필요하다. 배포물에 NOTICE가 포함되어 있으면 관련 귀속 고지의 읽을 수 있는 사본도 남겨야 한다. NOTICE는 라이선스를 변경하는 문서가 아니다.

LICENSE#L89-L128

상표 사용권을 일반적으로 주지 않으며 AS IS 무보증과 책임 제한이 있다. 프로젝트 이름을 출처로 식별하는 것과 로고·브랜딩을 공식 제품처럼 재사용하는 것은 구별해야 한다.

LICENSE#L138-L163

라이선스 파일은 문서 소스와 번역된 결과도 Source/Object 정의에 포함한다. 번역·발췌·개작을 재배포할 때도 원문 출처와 변경 사실, 해당 조건을 유지한다.

LICENSE#L26-L46

캡처한 전체 tree에는 NOTICE 계열 경로가 없다. 이는 이 source tree에 한정하며 배포 tarball의 고지를 확인한 것은 아니다. 코드·문서 전체가 아니라 필요한 짧은 명령과 독립 한국어 설명만 작성했다. 로고·원본 이미지·제3자 번들은 재현하지 않는다.

독립 분석·변경된 설명이며 프로젝트의 후원이나 보증을 뜻하지 않는다. LICENSE 원문 사본을 공개 증거 subset에 포함했다. 별도 권리를 확인하지 않은 미디어는 재현하지 않았다.

주장 원장

정적 근거와 실행 관찰은 구별한다. 32개 주장의 검증 범위와 미확인 연결을 함께 읽어야 한다.

ID 주장 판정 근거
C001 IPC transport 단계에 명시적 bearer token/peer credential 인증은 보이지 않는다. Unix socket 또는 Windows 127.0.0.1 TCP에 연결한 클라이언트의 JSON이 action dispatcher로 전달된다. HTTP 메서드 접두어 차단은 인증과 다르다. supported cli/src/connection.rs:996-1010,1103-1123; cli/src/native/daemon.rs:233-234,373-385,503-589
C002 ActionPolicy::load_if_exists는 경로 미설정뿐 아니라 파일 읽기·JSON 오류도 None으로 지운다. 따라서 이 helper 자체는 정책 로드 오류를 강제 중단으로 전달하지 않는다. 실제 daemon이 None을 어떻게 취급하는지는 미확인이다. supported cli/src/native/policy.rs:64-81; cli/src/native/policy.rs:123-132
C003 정책 helper는 deny → confirm → allow/default 순서다. default=deny라도 allow=[]이면 deny 분기가 실행되지 않아 목록에 없는 action이 Allow로 끝난다. allow 필드 누락과 빈 배열은 다른 의미다. supported cli/src/native/policy.rs:84-120; cli/src/native/policy.rs:163-205
C004 확인 UI를 켠 일반 CLI의 비TTY 입력은 자동 승인되지 않고 deny 요청 후 exit(1)한다. 단, 확인 UI를 켜지 않은 경로와 batch는 success 플래그만 실패 여부로 판단한다. confirmation_required와 success=true가 함께 오면 보류를 오류로 바꾸지 않는다. supported cli/src/main.rs:368-415,2079-2095; cli/src/main.rs:2222-2258,2288-2290; cli/src/native/daemon.rs:779-791
C005 allowedDomains는 launch JSON과 daemon 환경변수로 전달되지만 daemon config fingerprint에는 들어가지 않는다. action_policy와 confirm_actions는 fingerprint에 들어가 달라지면 기존 daemon을 재시작하는 경로가 있다. supported cli/src/main.rs:103-107,244-275,1747-1751,1847-1852,2022; cli/src/connection.rs:557-565,592-600,804-822; cli/src/connection.rs:1287-1307
C006 DomainFilter의 빈 목록은 무제한 허용이다. 비어 있지 않을 때 hostname 완전일치 또는 *.suffix 매칭을 하고 와일드카드는 apex 자체도 허용한다. check_url은 URL 파싱/hostname 부재를 오류로 반환하지만 IP 해석이나 목적지 IP 검증은 이 helper에 없다. supported cli/src/native/network.rs:84-134; cli/src/native/network.rs:666-701
C007 네트워크 보호는 CDP Fetch interception 설정과 JS API wrapper라는 두 층을 설치한다. wrapper는 fetch/XHR/WebSocket/EventSource/sendBeacon과 Worker/SharedWorker/importScripts를 다루고 RTCPeerConnection을 차단한다. Worker guarded bootstrap 생성 실패 때 원본 URL로 무방비 fallback하지 않도록 작성되어 있다. partially-supported cli/src/native/network.rs:269-428,439-469; cli/src/native/network.rs:346-428; cli/src/native/network.rs:703-721
C008 install_domain_filter는 CDP 설정 및 현재 context JS 예외를 오류로 반환한다. 반면 sanitize_existing_pages는 허용되지 않은 기존 페이지를 about:blank로 보내려 시도하되 navigate 실패를 무시하고 잘못된 URL/hostname 없는 페이지를 건너뛴다. supported cli/src/native/network.rs:136-215,460-469
C009 background CDP drain 실패 처리에 Unix/Windows 차이가 있다. Unix는 오류를 stderr에 기록하고 해당 tick autosave를 건너뛴다. Windows는 반환값을 사용하지 않고 autosave로 진행한다. supported cli/src/native/daemon.rs:278-297; cli/src/native/daemon.rs:432-444
C010 auth_save의 --password-stdin 읽기 실패/빈 값은 CLI에서 exit(1)한다. 읽은 비밀번호는 JSON password 필드에 넣어 공통 IPC 경로로 보낸다. CLI 인자의 password는 경고만 하고 거부하지 않는다. supported cli/src/main.rs:1554-1583; cli/src/connection.rs:1103-1123
C011 transport 재시도는 action 종류와 무관하게 같은 JSON 요청을 다시 전송한다. EOF·reset·broken pipe·EAGAIN은 최대 다섯 번 시도 대상이다. 따라서 성공 직후 응답만 유실된 경우 중복 side effect 방지 여부는 daemon의 idempotency 처리 확인이 필요하다. partially-supported cli/src/connection.rs:1013-1065; cli/src/native/daemon.rs:552-565
C012 일부 CLI 기능은 daemon 실행 정책 경로 밖으로 분기한다. install/upgrade, plugin registry, MCP/chat 등의 별도 entrypoint와 native::state::dispatch_state_command 로컬 처리가 있다. daemon 정책을 CLI 전체의 만능 권한 경계로 취급해서는 안 된다. supported cli/src/main.rs:1398-1409,1483-1506,1524-1533,1621-1648
C013 CI는 Rust fmt/clippy/test와 launcher 테스트를 선언한다. cross-platform Rust, native e2e, Windows integration, global install은 pull_request 이벤트에서는 실행하지 않는다. supported .github/workflows/ci.yml:26-68,140-175,198-202,255-259
C014 분석 SHA의 historical CI run은 failure다. Windows Rust의 Run Rust tests와 Native E2E의 Run e2e tests 단계가 실패했으며 Windows integration 및 Global Install은 skipped다. supported evidence/raw/pinned-ci-jobs.json
C015 release workflow는 main push와 수동 실행에서 버전을 비교하고 binary build 후 npm publish --provenance를 실행하도록 선언한다. publish job의 needs는 check-release와 build-binaries이며 이 파일에 CI workflow 성공 연계는 보이지 않는다. partially-supported .github/workflows/release.yml:3-7,233-253,324-348
C016 검사한 CI와 release workflow의 actions/checkout@v4 등 외부 action 참조는 full SHA가 아닌 가변 태그다. supported .github/workflows/ci.yml:15-19,51-57; .github/workflows/release.yml:27-32
C017 package.json의 bin은 ./bin/agent-browser.js다. 래퍼는 OS/CPU와 Linux musl 여부에 따라 파일명을 정하고, 파일이 없으면 오류로 끝내며, Unix에서 실행 비트를 복구한 뒤 원래 CLI 인자를 그대로 spawn한다. Windows ARM64는 source-built ARM64 파일이 있으면 우선하고 없으면 x64 에뮬레이션 파일로 간다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/package.json#L1-L34; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/bin/agent-browser.js#L19-L75; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/bin/agent-browser.js#L78-L126
C018 npm과 Cargo는 0.37.1을 선언한다. npm은 Node >=24 및 pnpm >=11을 선언하며 runtime dependency 목록 없이 devDependencies 빈 객체다. Rust manifest에는 Tokio, WebSocket, reqwest/rustls, aes-gcm, image, zip 등이 있다. 이는 네이티브 구현의 재료를 보여줄 뿐 모든 기능이 Rust-only라는 동작 증명이나 의존성 취약점 검증은 아니다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/package.json#L1-L10; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/package.json#L45-L54; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/Cargo.toml#L1-L45
C019 npm lifecycle postinstall은 현재 패키지 version과 플랫폼명으로 https://github.com/vercel-labs/agent-browser/releases/download/v${version}/${binaryName}를 만든다. 파일이 없으면 Node https.get으로 다운로드하고 301/302 Location을 재귀적으로 따른다. 수집 커밋을 고정해 읽었다는 것과 사용자가 npm 설치 시 받는 릴리스 실행 파일의 소스 동일성은 별개의 문제다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/package.json#L22-L34; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L34-L83; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L111-L163
C020 이 postinstall 다운로드 경로에는 checksum·서명·다운로드 크기 검증, redirect host allowlist, 명시적 timeout·redirect 횟수 제한이 없다. 이미 있는 파일도 존재 여부만으로 ready 처리한다. 이는 코드상 검증 부재이지 실제 공급망 변조가 발생했다는 뜻은 아니다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L54-L83; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L111-L126
C021 createWriteStream은 HTTP 상태를 알기 전에 목적지에 열리며, non-200 분기는 reject만 한다. 다운로드 실패는 로그 후 진행하고 종료코드 실패를 설정하지 않는다. 따라서 설치 단계가 끝나더라도 사용 가능한 바이너리가 있다고 단정할 수 없다. 다음 실행에서 남은 파일을 존재만으로 ready 처리할 위험은 정적 경로로 확인되지만 실제 재현은 하지 않았다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L54-L79; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L111-L126; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L140-L163; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L321
C022 postinstall은 Unix에서 chmod 0755를 적용하며 npm prefix -g로 찾은 agent-browser symlink를 삭제·재생성할 수 있다. symlink의 기존 목적지가 이 설치본인지 검증하는 조건은 없다. Windows는 예상 바이너리가 존재할 때 .cmd/.ps1 shim을 덮어쓴다. 즉 설치 권한은 전역 실행 진입점 변경까지 포함한다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L239-L270; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L278-L318
C023 이 postinstall은 Chrome을 직접 다운로드하지 않고 로컬 Chrome 존재를 확인한 뒤 필요하면 agent-browser install을 안내한다. .install-method에는 npm/pnpm/yarn/bun을 기록해 upgrade 경로에 전달하려는 의도가 보인다. 실제 upgrade 실행 명령·Chrome 다운로드 호스트/검증·Linux 시스템 패키지 설치는 지정된 구현 파일 밖이라 미확인이다. partially-supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L86-L109; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L166-L221; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/README.md#L57-L81
C024 AuthProfile은 URL·username·password·선택적 폼 selector를 포함한다. 새 저장은 프로필 전체를 JSON 직렬화해 AES-256-GCM으로 암호화하고 무작위 12바이트 IV와 16바이트 인증 태그를 base64 JSON envelope로 저장한다. 기본 위치는 ~/.agent-browser/auth/<name>.json이며 home 디렉터리를 찾지 못하면 temp/agent-browser/auth로 간다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L9-L55; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L151-L181; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L236-L253
C025 키는 AGENT_BROWSER_ENCRYPTION_KEY의 64자리 hex를 우선하며 없으면 ~/.agent-browser/.encryption-key를 읽는다. 자동 생성 키는 같은 사용자 디렉터리에 평문 hex로 저장한다. Unix dir 0700/file 0600 설정은 시도하지만 실패를 무시한다. Windows 전용 ACL 설정은 이 파일에 없다. 암호문과 키를 함께 읽을 수 있는 계정/백업/침해자에 대한 격리는 이 설계만으로 제공되지 않는다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L57-L148; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L236-L253
C026 중요 정적 결함: ensure_encryption_key는 get_encryption_key의 모든 오류를 키 없음과 동일하게 처리한다. 잘못된 환경 키·손상된 키 파일·키 읽기 오류도 새 키 생성 및 .encryption-key 쓰기로 이어진다. 잘못된 환경변수가 계속 있으면 복호화는 다시 그 환경변수를 우선하므로 새 저장본을 읽지 못하고, 기존 키 파일이 덮이면 예전 프로필도 복호화 불능이 될 수 있다. 오류 종류를 분리한 fail-closed 처리가 필요하다는 판단이며 실행 재현은 하지 않았다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L85-L112; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L114-L148; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L197-L224
C027 credentials_get와 auth_show 출력은 password를 생략하지만 내부 credentials_get_full은 평문 AuthProfile을 반환한다. decrypt_profile에는 평문 JSON 프로필을 허용하는 fallback도 있다. 따라서 새 저장은 암호화됨과 어떤 입력/실행 경로에서도 비밀번호가 LLM에 절대 노출되지 않음은 다른 주장이다. 후자는 login/출력/스크린샷/로그 소비자를 추가로 확인해야 한다. supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L197-L234; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L312-L324; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L374-L387
C028 소스 빌드 절차의 pnpm build — README에는 pnpm build가 있지만 이 커밋의 루트 package.json scripts에는 build가 없다. build:native와 build:dashboard는 별도다. README 절차를 검증된 온보딩으로 복제하면 안 된다. contradicted https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/README.md#L43-L55; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/package.json#L22-L34
C029 Node.js 24+와 pnpm 11+는 소스 빌드에만 필요 — 독립 네이티브 바이너리가 Node 없이 실행될 수 있다는 말과 npm 경로에 Node가 필요 없다는 말은 다르다. npm의 bin은 Node shebang의 JS 파일이며 lifecycle도 Node로 실행한다. 전역 symlink 최적화 성공 시에만 그 래퍼를 우회한다. pnpm은 npm 이용자의 필수라는 결론을 내리지 않는다. partially-supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/README.md#L77-L81; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/package.json#L7-L9; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/bin/agent-browser.js#L1-L15; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/scripts/postinstall.js#L239-L270
C030 snapshot -i는 interactive elements only — 코드는 interactive role 외 이름 있는 content role에도 has_ref를 붙이고 -i는 has_ref를 기준으로 출력한다. heading 같은 비조작 노드가 남을 수 있다. contradicted https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/README.md#L956-L976; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/snapshot.rs#L32-L43; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/snapshot.rs#L378-L399; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/snapshot.rs#L1121-L1127
C031 vault는 always encrypted이고 LLM never sees passwords — save_profile은 암호화를 강제하나 read는 평문 호환 입력을 허용한다. 일반 show/get은 비밀번호를 숨기지만 전체 시스템의 비노출 증거는 아니다. 세션 state 암호화와 vault 암호화를 혼동하지 말아야 한다. README 자체도 state 파일은 기본 평문이라고 경고한다. partially-supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/README.md#L690-L692; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/README.md#L844-L854; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L231-L253; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/auth.rs#L312-L324
C032 deterministic / Fast / No DOM re-query needed / optimal for LLMs — RefMap 저장 구현은 확인했다. 행동 시 요소 resolve 구현, 비교 벤치마크, 실제 토큰·지연·성공률은 이 자료로 확인하지 않았다. 광고 표현을 성능 사실로 올리지 않는다. partially-supported https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/README.md#L1212-L1238; https://github.com/vercel-labs/agent-browser/blob/8c15ff9f71ae60c7e99e66afe1e2d4b9bf414fe2/cli/src/native/snapshot.rs#L404-L438

README의 주장과 연결 위치

README 전체 번역은 하지 않는다. 아래는 원문이 연결한 개념을 원래 섹션 순서로 배치한 출처 맥락이다. 링크 대상의 내용을 별도로 검증했다는 뜻이 아니다.

agent-browser

skills.sh

원문 배지 skills.sh — 별도 사용권 미확인으로 재현하지 않음

Requirements

Chrome for Testing

Accessibility audits

axe-core

Import auth from your browser

State Encryption

Authentication

Security

https://github.com/login

Security documentation

Observability Dashboard

http://localhost

Configuration

JSON Schema

Headed Mode

WebGPU screenshots

WebGPU

https://` — 정상 URL로 해석되지 않아 비활성 표기로 유지

http://localhost` — 정상 URL로 해석되지 않아 비활성 표기로 유지

WebGPU docs page

Serverless (Vercel)

sandbox helper example

environments example

eve extension

eve

`@agent-browser/eve`

package README

eve example

CDP Mode

http://localhost:{port}` — 정상 URL로 해석되지 않아 비활성 표기로 유지

Browserless

Browserless

https://production-sfo.browserless.io` — 정상 URL로 해석되지 않아 비활성 표기로 유지

Browserless Dashboard

Browserbase

Browserbase

Browserbase Dashboard

Browser Use

Browser Use

Browser Use Cloud Dashboard

Kernel

Kernel

Kernel Dashboard

AgentCore

AWS Bedrock AgentCore

수집 범위와 남은 불확실성

공개 비인증 REST 22요청, API version 2026-03-10. 수집 시작 2026-09-11 07:07 UTC, 구조화 수집 마지막 07:15 UTC. 기본 main ref는 시작·끝에서 동일했다. 전체 inventory 612항목과 선택 16파일 12,472줄은 구분한다. 본문 조립·QA 시간은 소스 수집 시간과 별도다.

판독은 entrypoint·IPC·정책 helper·snapshot·auth·installer·CI 표본에 한정했다. 핵심 actions dispatcher, element resolve, provider/stream 전체, dependency lock 전문·SBOM·비공개 alert와 실제 바이너리 provenance는 미검증이다. 따라서 evidence trust C, runtime unknown을 유지한다.

실제 실행은 하지 않았다. checkout·worktree·install·build·test·run/import·container·hooks·submodules·LFS·filters·textconv 모두 미수행. Historical GitHub CI 결과는 타 시스템 관찰이며 이번 로컬 테스트의 통과가 아니다.

README 연결 31개는 원래 섹션 순서로 맥락을 보존했다. 26개는 링크 유지, 4개는 캡처 literal URL을 parser가 거부해 비활성 표기, 배지 1개는 독립 media 권리 미확인으로 재현하지 않았다. trailing backtick을 임의 제거해 새 URL을 만들지 않았다.

출처 원장은 append-only 원본을 보존하고 local_artifact 필드만 추가한 별도 파생 bundle로 정규화했다. 모든 성공 row의 SHA-256·바이트·실제 파일 동일성을 대조했다. 공개용 자료는 raw 댓글·프로필·개인 이메일을 제외한 별도 subset이다.

공개용 증거 인덱스 · 전달 영수증