Open feature request

Export a single site's live session so pup can carry it (replaces ab decrypt for the session case)

John Lauer · 13d ago

What pup needs

A verb that reads one site's live session out of the user's real signed-in Chrome/Edge (the browser nb-bridge already drives) and hands it back, so pup can set it in a pup window and act as the user on that site.

pup drives its own managed Chrome-for-Testing profile, not the user's real signed-in profile, so pup cannot see the user's existing sessions. nb-bridge is inside the real browser, where the user is already logged in, so this is a read nb is positioned to do and pup is not.

Why (the real-world case)

Signing a user into sites in pup keeps hitting a wall where the site refuses a fresh sign-in from pup's browser even with the right credential (x.com is the current example, adom/pup-bridge#136). But the user is already logged in to that site in their own Chrome. We don't need their password at all, we need the authenticated session carried over.

Until now the session came from ab's desktop_decrypt_browser_credentials, which reads cookies straight out of Chrome's sealed store. That path broke on Chrome 156 (adom/adom-bridge#254) and, more fundamentally, cracking Chrome's store from outside Chrome is a losing arms race against Chrome's hardening. Reading the session from inside the real browser, where nb already lives, sidesteps that entirely.

Shape (suggestion, nb owns the mechanism)

  • nb_export_site_session { domain } -> that site's cookies / storage for pup to set, scoped to the one registrable domain the user named.
  • Per-call consent, same as nb's other reaching-into-the-real-browser verbs. Values never printed or logged.
  • If more than one profile is signed in to that domain, return the list so the caller can ask which account.

Consumer

pup-bridge's pup_import_browser_logins { sessionFor } would call this instead of ab's decrypt helper. See the companion password-import request and adom/adom-bridge#254 for the full re-scope.

1 Reply

John Lauer · 13d ago

Built and working in nb 0.16.43 with extension 0.2.21 (insiders). Verified on AdomLapper against a real signed-in session.

nbrowser_export_site_session { domain, confirm: true, reason }

Reads that one registrable domain's cookies from inside the user's real browser (chrome.cookies, which nb already uses for login_state and clear_cookies), so nothing cracks Chrome's sealed store and nothing breaks on the next hardening bump. No UI driving, no OS reauth needed, works in the background.

The one design decision you should push back on if you disagree

The cookie values are never in the reply. They are written to a file on the user's machine, owner-only, and the caller gets handoffPath plus counts.

The reason is the shape of our own system: the AI asking for this usually runs in a cloud container, across a relay. If the values came back in the tool result they would be in a transcript, a context window and whatever logs sit in between, forever, for a credential that is live. So the values move machine-locally, which is where pup already is.

What a caller sees:

{ ok: true, domain: "adom.inc", cookieCount: 2, authCookieCount: 1,
  hosts: ["adom.inc", "wiki.adom.inc"],
  handoffId: "session-...-7eddffa5948d",
  handoffPath: "C:\\Users\\john\\.adom\\bridges\\native-browser\\handoff\\session-....json",
  expiresInSec: 600 }

pup reads handoffPath on that machine and imports it. File shape: { id, kind, verb, domain, profile, reason, createdAt, cookies: [{ name, value, domain, path, secure, httpOnly, sameSite, expirationDate, hostOnly, session }] }, which is what CDP Network.setCookie or chrome.cookies.set want.

The rest of the contract

  • Per-call consent. Without confirm: true it refuses with confirm_required and tells the AI to ask the user by name: "I can carry your x.com session into pup so it can act as you there. OK?" reason is required and recorded.
  • One domain per call. There is deliberately no export-everything.
  • Self-cleaning. The file expires in 10 minutes, and nbrowser_drop_handoff { handoffId } deletes it the moment pup has imported it. Call it.
  • Nothing is logged. The activity trail records the verb, domain, profile, caller and reason, never a value. Verified: no cookie value in the trail.
  • Wrong profile is an answer, not a silence. no_session says the user may be signed in under a different profile and points at nbrowser_profiles and nbrowser_login_state.

Verified on AdomLapper

Consent gate refuses without confirm. With confirm, 2 cookies exported for the wiki, file present on the machine and readable only by SYSTEM, Administrators and john, no value key anywhere in what crossed the relay, drop_handoff removed it, directory empty afterwards. The battery covers all of it (consent gate, no leak, file written, drop) and fails if a cookie value ever appears in a reply.

Over to pup: point pup_import_browser_logins { sessionFor } at handoffPath, then call nbrowser_drop_handoff. Tell me if the file shape needs anything else, for example localStorage for sites that keep a token there rather than in a cookie. That is a small addition and I left it out on purpose until someone needs it.

Log in to reply.