[Bug]: A site's Copy button in a server-runtime Browser tab reports success but never reaches the local clipboard#32034

opened6d agobySSean-R-Wilson

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Related: #26600 reported this and was closed as covered by #26633. That PR fixed native Edit > Copy/Cut and Cmd+C/X, and says "Website Copy buttons remain outside this fix." #19561 stopped forwarding page clipboard writes on purpose, after #18259. #27402 and #27462 are about html_render visuals, a different surface. This issue is the part still open: a website's own Copy button.

Area

apps/server (server-runtime preview browser), plus the web client's clipboard relay

What happened

An agent opened a developer portal in a Browser tab and I signed in. The page has Copy buttons next to the app's credentials. I clicked Copy in the tab and pasted into a request_secret card. Seven times in a row the card saved old, unrelated text that was already on my clipboard. Nothing told me the copy had failed, so I kept trying. The right values only came through once I opened the same page in my normal browser and copied there.

Steps to reproduce

  1. Serve this page over loopback, for example with python3 -m http.server 47831 --bind 127.0.0.1:

    html
    1<button onclick="navigator.clipboard.writeText('t3-clipboard-test-async-' + Date.now()).then(() => out.textContent = 'writeText resolved')">writeText</button>
    2<button onclick="const t = document.createElement('textarea'); t.value = 't3-clipboard-test-exec-' + Date.now(); document.body.append(t); t.select(); out.textContent = 'execCommand returned ' + document.execCommand('copy'); t.remove()">execCommand copy</button>
    3<p id="out"></p>
  2. Open it in a server-runtime Browser tab. An agent's preview_open gives one; t3_preview_list shows runtime: "server".

  3. Put a marker on the local clipboard: printf marker | pbcopy.

  4. Click a button, then run pbpaste (or paste anywhere). Reset the marker before the next button.

My run on 6 Nov 2026, with an agent clicking through preview_act:

PathWhat the page sawLocal clipboard after
navigator.clipboard.writeText buttonpermissions.query({name: "clipboard-write"}) is granted; writeText resolvedUnchanged
document.execCommand("copy") buttonReturned trueUnchanged
Select text, agent sends Cmd+CA copy event firedUnchanged (expected: only the viewer's own keys are relayed)

The tab ran in chrome-headless-shell 156.0.8078.70 under the environment's t3 serve, on the same Mac as the desktop app, so pbpaste read the right clipboard. The original failure above was my own mouse clicks in the tab, so a human viewer's clicks fail the same way.

Expected behavior

Clicking a site's Copy button in the Browser tab puts the copied text on my local clipboard, as it does in a normal browser and in a desktop-rendered tab. If T3 can't do that safely, it tells me the copy didn't reach my clipboard, so I don't paste stale text.

Actual behavior

The page is told the copy worked (writeText resolves, execCommand returns true), so the site behaves as if it copied. The text stays inside the headless browser. My local clipboard keeps its old contents, and the next paste silently uses them.

Diagnosis

Read on main at 6577c6b. The same code is in v0.1.2 and v0.1.5.

  • Server-runtime tabs run in chrome-headless-shell, which keeps its own in-memory clipboard, separate from the OS clipboard.
  • ServerBrowser.ts L1266-L1270: prepareContext grants clipboard-write to every headless context, so page writes succeed and report success.
  • ServerBrowser.ts L426-L467: the isolated-world CLIPBOARD_SCRIPT records copied text only while keying is set by a trusted Ctrl/Cmd+C or X keydown.
  • ServerBrowser.ts L2438-L2459: the server reads that text and pushes { _tag: "clipboard" } to the viewer only when the viewer sends a copy or cut key. A pointer click never triggers a read.
  • ServerBrowserSurface.tsx L106-L123: the client writes pushed text with navigator.clipboard.writeText, and already falls back to a "The page copied text" toast with a Copy button.
  • Desktop-rendered tabs are fine: BrowserSession.ts L21-L24 and L319-L344 allow clipboard-sanitized-write in both permission handlers (#3738).

This is the trade-off #19561 describes: "Copy buttons that only call navigator.clipboard.writeText stop reaching the viewer's clipboard; the copy and cut keys still do." From inside the tab the user can't see which kind of tab they have, or that the copy went nowhere.

Suggested fix

Keep the rules from #19561 and #18259: no page-callable helper, no user activation granted to pages, the shared headless clipboard is never read, and agent input or idle mouse movement forwards nothing. Then:

  1. Treat a controlling human viewer's pointer click like the copy keys: capture what the page copies while that click is dispatched and read it right after. execCommand("copy") buttons already fire a copy event the isolated world can see. navigator.clipboard.write/writeText fire no event, so they need a main-world hook whose text is read only during a viewer click.
  2. Deliver click-originated text through the existing "The page copied text" toast, so the local clipboard changes only on a local click.
  3. If forwarding is rejected, at least stop the silent false success: after a viewer click in which the page copied, show a notice that the copy stayed in the tab and that selecting the text and pressing Cmd+C works.

Agent brief

Category: bug

Summary: A site's Copy button in a server-runtime Browser tab should reach the viewer's local clipboard, or clearly say it didn't.

Acceptance criteria:

  • With a human viewer in control of a server-runtime tab, clicking a button that calls navigator.clipboard.writeText(x) puts x on the viewer's local clipboard, directly or through one local click on a toast.
  • The same holds for a button that copies with document.execCommand("copy").
  • Page clipboard writes not caused by the viewer's own click (timers, agent preview_act clicks, mouse moves, wheel) forward nothing.
  • Pages still gain no user activation from T3 helpers, and the shared headless clipboard is never read.
  • Cmd+C/X and native Edit > Copy/Cut keep working as #26633 verified.

Out of scope:

  • Paste from the local clipboard into the tab.
  • html_render visuals (#27402).
  • A "capture to secret" action (suggested in #26600).

Impact

Major degradation or frequent failure

Version or commit

T3 Code (Beta) desktop 0.1.2; environment server t3 0.1.5; same code paths on main @ 6577c6b

Environment

macOS 27.0.1 (26A434), Apple silicon. Server-runtime tab in chrome-headless-shell 156.0.8078.70, started by the local t3 serve.

Workaround

Open the page in a normal browser and copy there (what worked for me), or select the value in the tab and press Cmd+C (relayed since #26633).


Investigated with Claude Opus 5.5 (Claude Code in T3 Code).