SailfishOS Security Metasploit Ruby Porting

Bringing Metasploit to SailfishOS — A Port Worth Making

How we wrestled a full penetration-testing framework onto a niche mobile OS, and built a shrinker script that makes the next port a whole lot easier.

Security Research March 2026

When we first floated the idea of running Metasploit Framework on SailfishOS, the polite response was scepticism. SailfishOS is a Linux-based mobile operating system with a small but passionate community — it was never designed to host a several-hundred-megabyte Ruby application stack intended for desktop-class penetration testing. And yet, here we are.

This post walks through why we did it, the real obstacles we hit, and — most importantly — the tooling we built along the way that will make future security work on the platform significantly less painful.


Why SailfishOS?

SailfishOS occupies a unique niche: it is a genuinely independent, Linux-kernel-based mobile OS that does not depend on Google or Apple infrastructure. That independence makes it attractive for privacy-conscious users, security researchers, and organisations that operate in regulated environments. It also means that the security tooling that takes for granted Android's package ecosystem simply doesn't exist here.

A phone running a real Linux kernel with a fully functional shell is an extraordinary field tool. Being able to run Metasploit on it natively — rather than through a remote shell into a laptop — opens up on-device payload testing, local network reconnaissance, and controlled exploit demonstrations without bringing additional hardware.

The core thesis: if the OS runs a proper Linux kernel and we can get Ruby installed, Metasploit should follow. The devil, as always, is in the details.

The Challenges We Actually Ran Into

01 — Ruby on a mobile OS

SailfishOS ships without Ruby in its default repository. We used build.sailfishos.org — Sailfish's OBS-based build service — to compile Ruby and its dependencies and package them as proper RPMs. This required careful dependency resolution within the build service: several native extensions in Metasploit's gem tree link against OpenSSL and libpcap, both of which needed matching development headers present in the OBS build environment.

02 — Gem dependencies and native extensions

Metasploit has a notoriously large gem dependency tree. Many gems compile C extensions at install time. On a device with limited RAM and a slower ARM processor, several of these failed silently — the compile step would OOM-kill mid-way through, leaving a half-installed state that broke subsequent attempts. We ended up cross-compiling the most expensive native extensions in the SDK and shipping pre-built versions.

03 — Storage and filesystem constraints

A full Metasploit checkout, with all modules, exploits, and documentation, weighs in at over 500 MB. SailfishOS devices typically have limited internal storage partitions assigned to the system side. This was the most immediate blocker, and the one that ultimately drove the creation of the shrinker script.

500 MB+
Full Metasploit checkout size
~87 MB
Post-shrinker footprint
~83%
Reduction in size

04 — SELinux and Sailfish security policies

SailfishOS enforces a Sailfish-specific security framework on top of the Linux kernel. Some Metasploit components — particularly those that open raw sockets or bind to privileged ports — tripped security restrictions. We identified the required capability grants and documented a minimal policy exception so the install could run without wholesale disabling of system protections.

The Shrinker Script

The shrinker script is the most practically reusable piece of work to come out of this effort. It is a targeted pruning tool that strips Metasploit down to a well-defined, functional core — removing documentation trees, redundant resource files, locale data for unused languages, historical exploit modules that target end-of-life platforms, and build artefacts that have no runtime purpose.

bash — shrinker.sh (simplified excerpt)
#!/usr/bin/env bash
# metasploit-shrinker — strip non-essential content for embedded/mobile targets
# Usage: ./shrinker.sh <msf_root> [--dry-run]

MSF_ROOT="${1:?provide metasploit root}"
DRY_RUN="${2:-}"

remove() {
  if [[ "$DRY_RUN" == "--dry-run" ]]; then
    echo "[dry] would remove: $1"
  else
    rm -rf "$1" && echo "[removed] $1"
  fi
}

# Documentation
remove "$MSF_ROOT/documentation"
remove "$MSF_ROOT/data/logos"

# Locale data for unused languages
for locale_dir in "$MSF_ROOT"/locale/*/; do
  lang=$(basename "$locale_dir")
  if [[ "$lang" != "en" ]]; then
    remove "$locale_dir"
  fi
done

# Legacy platform modules (XP-era, pre-2010 servers)
remove "$MSF_ROOT/modules/exploits/windows/smb/ms03_026_dcom.rb"
remove "$MSF_ROOT/modules/exploits/windows/smb/ms04_011_lsass.rb"
# ... (full list in shrinker_modules.conf)

# Build artefacts
remove "$MSF_ROOT/.git"
find "$MSF_ROOT" -name "*.md" -not -path "*/lib/*" -delete
find "$MSF_ROOT" -name "*.txt" -path "*/documentation/*" -delete

echo "Done. Final size: $(du -sh "$MSF_ROOT" | cut -f1)"

The script is driven by a companion configuration file — shrinker_modules.conf — which lists module paths to exclude by category. This separation of logic and configuration is intentional: the same script runs unchanged against future Metasploit versions; only the config file needs updating as the module set evolves.

What the shrinker keeps

The design principle was ruthless subtraction with a safe fallback. The shrinker preserves all active modules targeting current platforms, the full auxiliary and post-exploitation trees, the core libraries and mixins that other modules depend on, and the msfconsole and msfvenom entry points. If there is any ambiguity about whether a module might be a dependency, it stays.

--dry-run first, always

A --dry-run flag prints every path that would be removed without touching the filesystem. This was essential during development — we ran dry passes, checked the output list against known working module inventories, and only committed to a live run once the diff looked correct. We recommend making dry-run the default in any CI pipeline that prepares Sailfish packages.

The Resulting Install Flow

After the shrinker work, the package is built and published via build.sailfishos.org. The end-to-end experience on a fresh SailfishOS device is then simply:

[device] $ pkcon install msf3
Resolving dependencies...
Installing packages... done.

[device] $ msfconsole
=[ metasploit v6.x.x ]
+ -- --=[ 2300+ exploits | 1200+ auxiliary | ... ]
msf6 >

How This Eases Future Work

The shrinker script is the gift that keeps giving. Every subsequent Metasploit update cycle — which happens frequently, given the project's active development pace — can now be handled by pulling the latest release, running the shrinker, and rebuilding the package. Without the script, each update would require manually re-auditing hundreds of megabytes of content.

Beyond updates, the shrinker approach generalises cleanly to other constrained targets. Any embedded Linux environment — a router, an IoT gateway, a hardened single-board computer — that needs Metasploit can start from the same script with a different shrinker_modules.conf. The architecture of keeping the pruning logic separate from the pruning configuration was a deliberate investment in reusability.

We also produced a compatibility matrix documenting which Ruby versions and native gem versions have been validated on Sailfish device classes. This lives alongside the shrinker in the repository and will serve as the reference point when SailfishOS pushes a major platform update.

The shrinker does not just save storage space — it saves the maintenance overhead of understanding what changed between releases. That is arguably the more valuable outcome.

What's Next

There are a few open threads we are still pulling on. Native UI integration — a simple Silica/QML front-end that wraps msfconsole for common workflows — would make the tool genuinely ergonomic on the device. We are also looking at packaging the shrunken distribution as an official Chum or OpenRepos package so that interested researchers can install it without building from source.

On the security policy side, we want to submit the minimal capability documentation upstream to the SailfishOS developer community so that other applications with similar network requirements can benefit from the analysis we have already done. Source code available here

Closing Thoughts

Porting Metasploit to SailfishOS was not a quick weekend project. It required understanding both the Metasploit codebase deeply enough to know what could safely be removed, and the SailfishOS platform deeply enough to know what the OS would and would not tolerate. The shrinker script captures that understanding in executable, repeatable form.

If you are working on security tooling for alternative or constrained Linux platforms, we hope the approach — and especially the shrinker pattern — is useful. The repository is open; contributions to the module exclusion list from the broader community are very welcome.