Skip to content

fix(clipboard): neutralize termflow OSC 52 clipboard hijacking at the source#484

Merged
mpfaffenberger merged 2 commits into
mpfaffenberger:mainfrom
thomwebb:main
Jun 17, 2026
Merged

fix(clipboard): neutralize termflow OSC 52 clipboard hijacking at the source#484
mpfaffenberger merged 2 commits into
mpfaffenberger:mainfrom
thomwebb:main

Conversation

@thomwebb

Copy link
Copy Markdown
Contributor

Problem

termflow's RenderFeatures.clipboard defaults to True. When the renderer
finishes a code block, it emits an OSC 52 escape sequence
(\x1b]52;c;<base64>\x07) that modern terminals (iTerm2, Kitty, Alacritty,
WezTerm, tmux) silently interpret as a clipboard-write command — clobbering
whatever the user had copied, with no prompt or consent.

PR #335 added explicit RenderFeatures(clipboard=False) at the two known
TermflowRenderer instantiation sites, but this is whack-a-mole: any future
code path, a new termflow version with changed defaults, or a missed
instantiation site reintroduces the bug.

Fix

Added patch_termflow_clipboard() to pydantic_patches.py. It replaces
termflow.render.renderer.Renderer._copy_to_clipboard with a no-op at
startup (via the existing apply_all_patches() call in cli_runner.py).

This kills the behaviour at the source regardless of:

  • Per-call RenderFeatures(clipboard=...) flags
  • termflow config files (~/.config/termflow/config.toml)
  • Future instantiation sites that forget the flag
  • New termflow versions that change defaults

The existing per-site clipboard=False flags are left in place as
defense-in-depth and for documentation value.

Testing

  • test_copy_to_clipboard_is_noop — confirms the patched method writes nothing
  • test_code_block_render_emits_no_osc52 — end-to-end: renders a code block
    with clipboard=True and asserts no \x1b]52 sequence leaks into output
  • test_patch_does_not_crash_without_termflow — verifies graceful failure if
    termflow is not installed

All 26 tests in test_pydantic_patches_full_coverage.py pass.

Files Changed

File Change
code_puppy/pydantic_patches.py +patch_termflow_clipboard() no-op patch, registered in apply_all_patches()
tests/test_pydantic_patches_full_coverage.py +TestPatchTermflowClipboard class with 3 regression tests

thomwebb added 2 commits June 16, 2026 17:45
termflow's RenderFeatures.clipboard defaults to True, causing it to emit
OSC 52 escape sequences that silently overwrite the user's clipboard with
every rendered code block. The patch replaces Renderer._copy_to_clipboard
with a no-op to prevent this behavior at the source, ensuring robust
protection regardless of per-call feature flags or future code paths.

- Add patch_termflow_clipboard() to monkey-patch Renderer._copy_to_clipboard as a no-op
- Integrate the patch into apply_all_patches() for automatic activation
- Update module docstring to reflect broader third-party library patching scope
- Ensure all changes are idempotent and fail silently if dependencies are absent
- Verify that _copy_to_clipboard is a no-op and produces no output
- End-to-end test confirming no OSC 52 escape sequences appear in rendered output
- Guard against crashes when termflow is not installed
@mpfaffenberger mpfaffenberger merged commit 0dc81e7 into mpfaffenberger:main Jun 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants