Skip to content

Back to the catalog

Compromised Flutter package on pub.dev contains XCSSET malware
aikido.devwriteup

Compromised Flutter package on pub.dev contains XCSSET malware

Aikido Security discovered a variant of the XCSSET macOS worm hidden in universal_file_viewer, a Flutter file-preview package on pub.dev (~500 downloads) — the first compromised package found on that registry. The infection was not a targeted supply-chain attack but resulted from the maintainer's machine being infected with XCSSET, which auto-injects malicious build hooks into every Gradle, Xcode, and git project it finds; the poisoned example/ directory (Android Gradle build, iOS/macOS Xcode project files) shipped in the package tarball. The writeup details XCSSET's four-stage infection chain, its android_finder/git_finder/replicator_finder propagation modules, Launchpad-tile persistence, and theft modules targeting Chrome, Safari, Firefox, Telegram, Notes, and clipboard data, plus C2 domain and file-artifact IOCs.

TL;DR XCSSET macOS worm turned up inside the example/ build files of a pub.dev Flutter package after the maintainer's machine was infected, spreading via poisoned Gradle/Xcode/git hooks and stealing browser, Telegram, and clipboard data.
Document

What it is

A variant of the XCSSET macOS worm shipped inside universal_file_viewer version 0.1.5 on pub.dev. The infection is incidental, not targeted — the maintainer's machine was infected and the worm auto-injected build hooks into files that then got published. The important operational fact the summary omits: dependents are not at risk. lib/ is clean; adding the package to pubspec.yaml and building your own app triggers nothing. Only someone who clones the repo and explicitly builds the example/ app locally is exposed.

How it works — the injected hooks (detection strings)

Three build configs in example/ carry independently injected hooks, each obfuscated to defeat string scanners:

  • example/android/app/build.gradle.kts — a preBuild hook that reconstructs xxd at runtime via printf xAxd | tr -d A, decoding a hex blob to a curl to 5yotmxcc54l9xda[.]ru/a (tag p=android_kotlin). Fires on every Gradle build, output discarded.
  • example/ios/Runner.xcodeproj/project.pbxproj and example/macos/.../project.pbxproj — a PBXBuildRule firing on any .md file, running sh -c "${A3EA261}". iOS variant (printf bdase64 | tr -d d) hits qdgs232i-q[.]ru; macOS variant (printf xxVd | tr -d V) hits ejntin6hkjt7gj2[.]ru; both tag p=xcode_rule.

Post-infection, the worm re-spreads via android_finder (Gradle preBuild), git_finder (polymorphic .git/hooks/pre-commit doing base64 --decode | base64 --decode), and replicator_finder (Xcode Run Script phase). Persistence swaps the Dock's Launchpad tile for a fake bundle under ~/Library/Caches/vyf[.]lttzw[.]snjgwq/ impersonating com.apple.launchpad.launcher. All theft runs in-memory via osascript; exfil goes to /u as AES-256-CBC-encrypted multipart POST.

Preconditions / Affected

macOS developers who cloned and built the example/ app; anyone whose Gradle/Xcode/git projects were touched by an already-infected machine. Windows/Linux users of the package are unaffected by execution. The page notes this is still ongoing — other maintainers are pushing infected projects unknowingly.

What to do — IOCs to grep

Scan repos and machines for these artifacts:

C2 domains

5yotmxcc54l9xda[.]ru
qdgs232i-q[.]ru
ejntin6hkjt7gj2[.]ru

File artifacts

project.pbxproj  → PBXBuildRule with  sh -c "${A3EA261}"
build.gradle(.kts) → printf xAxd | tr -d A  (reconstructs xxd)
.git/hooks/pre-commit → base64 --decode | base64 --decode  OR  xxd -p -r | xxd -p -r

Also check the Dock for a Launchpad tile pointing at the fake Caches bundle above, and browser/Telegram data theft indicators (~/Library/ASafari/, replaced Telegram.app, firefox_browser_data.zip).

Caveats

Only ~500 downloads and a narrow trigger (local example build), so blast radius via this package is small — but the worm's self-propagation means an infected developer machine spreads to unrelated Gradle/Xcode/git projects regardless of this package.

Organisations named here

  • universal_file_viewer
  • XCSSET

Technologies named here

  • Flutter
  • macOS
  • Android
  • Telegram
  • Chrome
  • pub.dev