On 8 September 2026 Aikido Security reported a compromised package on pub.dev, the Dart and Flutter registry. The package is universal_file_viewer version 0.1.5, which had about 500 downloads. Aikido says it is the first compromised package it has detected on pub.dev, and that the malware is a variant of XCSSET, a macOS worm.
What happened
According to Aikido (researcher Ilyas Makari), the package traces back to a compromised GitHub repository. The lib/ folder is clean. The infected files are in example/, which ships in the published tarball but is not compiled into apps that depend on the package.
So the risk is not flutter pub add. It is a developer who clones or unpacks the package and builds the example app locally. Aikido says the maintainer's own infected machine spread the worm into the published files, and that this was not a targeted attack.
The infected build configuration, per Aikido:
- an Android Gradle
preBuildhook inbuild.gradle.kts - Xcode
PBXBuildRuleentries inproject.pbxprojfor iOS and macOS - pre-commit hooks under
.git/hooks, used to spread to other projects
Aikido describes staged loading with AES-256-CBC, in-memory execution through osascript, and theft of browser credentials and cookies, Telegram sessions, Notes, Reminders and Calendar data, clipboard contents and files in home directory folders. Its listed domains are 5yotmxcc54l9xda.ru, qdgs232i-q.ru and ejntin6hkjt7gj2.ru.
Confirmed, reported and unknown
Reported by one researcher, with indicators published: the package, version, infected files, behavior and domains. I found no registry statement in what I fetched.
Unknown: whether pub.dev has removed the package, whether other versions are affected, how many people were infected, the maintainer and repository identity, and who runs the campaign. Aikido says a GitHub search shows other maintainers still pushing infected projects, with no count.
What to do now
- Search for
universal_file_viewerinpubspec.lock. If present, it is safe to say a dependency alone did not run the malware, but check whether anyone built the example. - On any Mac that built an
example/project from this package, treat the machine as compromised. Isolate it, then reimage. - Rotate browser saved passwords, session tokens, Git and cloud credentials used on that Mac.
- In your own repositories, search for the artifacts Aikido lists:
grep -rn "printf xAxd | tr -d A" --include=build.gradle.kts .
grep -rln 'sh -c "${A3EA261}"' --include=project.pbxproj .
find . -path "*/.git/hooks/pre-commit" -exec grep -l "base64" {} +
- Review recent commits for build files you did not change.
How this could have been avoided
- Treat
example/,test/andtool/folders from third party packages as untrusted code. Open them in a disposable VM, not on a developer Mac with browser sessions. - Build and review pre-commit hooks from a version controlled template. A
.git/hooks/pre-commitfile with nested base64 decoding is easy to flag. - Add a check in CI that fails when a
PBXBuildRuleor GradlepreBuildhook contains shell commands that decode strings. - Keep browser sessions and cloud credentials off the machine used to run unfamiliar sample apps.
- Publishers should verify what is in the tarball before release by running
dart pub publish --dry-runand reading the file list.
Quick check
Does adding universal_file_viewer as a dependency run the malware?
Per Aikido, no. The infected files are in the example folder, which is not compiled for dependents. Building the example is the risk.