Shadow, an iOS jailbreak detection bypass built as a Theos tweak
A jailbreak detection bypass for modern iOS jailbreaks.
At a glance
- What is it?
- Shadow is a jailbreak detection bypass for iOS, written in Objective-C with Logos preprocessing and packaged as a Theos project with four build lanes for the different jailbreak styles. Its most interesting feature is the honesty of its compatibility section, which states plainly that the ranges are declared package metadata rather than a tested matrix.
- Who is it for?
- Shadow suits a security researcher who needs to run an app on a jailbroken device without the app noticing, and it suits someone maintaining per-app configuration across several jailbreak flavours. It is the wrong tool for an end user, since it requires a jailbreak, a package manager and a build of the tweak, and it is the wrong tool if you need a guaranteed result on a specific app, because the README states there is no guarantee every app and detection SDK works everywhere.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Logos, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the tweak actually does, and where it lives
Shadow is described as a modern jailbreak detection bypass, and the primary language of the repository is Logos, which is the Objective-C preprocessor used by Theos to write method swizzles in a readable form. It is a tweak in the jailbreak sense: a dynamically loaded library that hooks functions in other processes.
The home page is ios.jjolano.me, and the package identifier is me.jjolano.shadow. The repository layout shows a classic Theos project. There is a build.sh at the root, a Makefile that includes Theos makefiles, build-support/ holding the lane definitions, packaging/ holding the package layout and maintainer scripts, src/ holding the source, tests/ with its own README and a Makefile, vendor/ for vendored code, and scripts/ and .github/ for the build pipeline.
The Makefile shows the shape of the build in four lines. It includes build-support/build-lanes.mk, sets THEOS_LAYOUT_DIR_NAME to packaging/layout, and then adds four subprojects: src/Shadow.framework, src/Shadow.dylib, src/ShadowCore.dylib and src/ShadowSettings.bundle, plus src/shdw as a command line tool. So the shipped artefact is not one binary but a framework, a core dylib, a settings bundle for the Settings app and a command line helper.
The project also carries AGENTS.md, CLAUDE.md and a .clang-format file, and the licence is BSD 3-Clause. The README's funding note asks for sponsorship or a coffee, which is the usual arrangement for a project maintained by one person.
Four build lanes, because iOS jailbreaks stopped being one thing
The build matrix is the part of this project that is genuinely hard, and it is why the repository is structured around lanes rather than around a single configuration.
The lanes are rootful-legacy, rootful-modern, rootless and roothide, and you build one at a time. The README gives the two commands:
.github/scripts/build-deps.sh rootful-modern
./build.sh rootful-modernAnd it points at build-support/lanes.sh for the matrix itself. The tests are run with make -C tests test.
Each lane corresponds to a different way of injecting a tweak into the system, and the difference matters at the file system level rather than only in the source. The Makefile shows one of the consequences directly. The rootless scheme stages the whole layout under /var/jb, and after staging the build removes the rootful ruleset watcher plist and renames the rootless one into place. The reverse happens for the other schemes. In other words, the same source produces four different packages whose contents and paths differ, and the build has to select the right one rather than shipping all of them.
The declared package ranges are in the compatibility table, and they cover rootful legacy on iOS 9 to 13, rootful modern on 14 and later, rootless on 15 and later, and RootHide on 15 to 17. Each row names the architecture it targets, with iphoneos-arm for the rootful lanes, iphoneos-arm64 for rootless and iphoneos-arm64e for RootHide.
The architecture column is not decoration either. A binary built for arm64 is not arm64e and not the reverse, which is why a package range per architecture is the only way to express the support matrix at all.
The compatibility section says what the table does not prove
The most valuable paragraph in the README is the one right after the compatibility table, and it is worth quoting in full rather than paraphrasing. There is no guarantee every app and detection SDK works everywhere. Then: these are declared package ranges, not a device-tested version matrix. CI builds all four lanes and checks package metadata and Mach-O compatibility, and public host tests do not verify hook installation or behaviour on each iOS version. And finally, an open-ended range does not establish compatibility with future releases.
That is a README writing about itself honestly, and it is unusual. A jailbreak tweak whose entire purpose is to make an app think it is not jailbroken has a strong incentive to overstate coverage, because a claim of universal support is more attractive than a claim of probable support. This project does the opposite: it distinguishes what CI actually checks, which is the build and the package metadata, from what nobody has verified, which is whether the hooks install and work on a given iOS version.
The distinction between a declared range and a tested result generalises to every row of the table. iOS 15 and later for rootless means the package declares that range, not that someone has run the tweak on every release in it. And a 14+ range says nothing about iOS versions that have not been released yet.
The legal note at the end of the README is the other unusual line. It cites the Copyright Act, RSC 1985, c C-42, s 41.12, which is Canadian legislation on circumventing technological protection measures. Naming the statute in a jailbreak tool's README is a deliberate signal about what the author thinks the legal situation is, and it is a reminder that a tool can be technically interesting and legally contested at the same time.
Configuration lives in the Settings app, and a helper keeps it in sync
The usage story is short. You open the Settings app, find Shadow, and configure either global defaults or a per-app configuration. The command line tool shdw handles the second half, with shdw -d keeping the app ruleset in sync.
That is a sensible design for a tweak of this kind, and the reason is that a bypass that applies the same way to every app is rarely what anyone wants. Detection SDKs differ in what they probe, and a bypass that is too broad can break other apps that legitimately check for a jailbreak, or trip protections that were not the target. A per-app ruleset lets you enable the bypass for one app and leave everything else alone, which is both more precise and easier to troubleshoot when something else misbehaves.
The shdw tool exists because that configuration has to be written into a place the tweak reads at runtime, and the -d flag synchronises the app ruleset. The package metadata in the Makefile shows a related mechanism: there is a launch daemon, me.jjolano.shadow.watcher.plist, which is a watcher, and the rootless build swaps in a different watcher plist. So the tweak has a background component that reacts to configuration changes rather than only reading them at launch.
The dependency list in the install section explains the ecosystem. Shadow needs AltList and libSandy from opa334, and HookKit 3.0.4 or newer from jjolano, with a lower 2.5.0 floor on rootful legacy. Injection Foundation by PoomSmart is recommended. That is a stack of other people's packages, which means the versions of those packages are part of your compatibility calculation, and it means the tweak's own release history is not the whole story of whether it will install.
Troubleshooting advice that assumes you know what you are doing
The troubleshooting section is three bullets and each one is a debugging strategy rather than a fix.
The first is to disable other tweaks per-app using Choicy. The second is to downgrade the app and not to stack multiple bypass tweaks. The third is that on rootless and semi-untethered systems you should test in a stock jailed state to isolate.
That third point is the most useful, because it is about establishing a baseline. On a semi-untethered device the environment is in flux, with the jailbreak state changing between reboots, so a problem you are seeing may not be the bypass at all. Testing with the tweak disabled and the device in a known state separates the bypass from the environment.
The advice not to stack bypass tweaks is the same idea from the other direction. Two tools that both try to hide the same evidence can interfere with each other, and the result is a bug in the interaction rather than in either tool. Downgrading the app, which is the second half of that bullet, is the standard advice for apps that detect jailbreaks, since developers add detection over time and an older build often lacks it.
None of this is specific to Shadow, which is a sign of a well-informed project. The advice is the accumulated knowledge of people who have debugged a lot of hooks, and it is the kind of thing the documentation of a project with real field experience tends to contain.
Where this sits, and who should not reach for it
The honest assessment is that Shadow is a specialist tool with a narrow audience and a legal grey area that it does not pretend to avoid.
The legitimate use is security research and testing. If you are building an iOS application and want to know whether your jailbreak detection actually holds, running the app on a jailbroken device with the detection bypassed is how you find out. That is a defensive use, and it is the same category as running a debugger against your own binary.
The illegitimate use is running a third party's app with its protections disabled in order to do something the protections were there to prevent. The README's legal note is a pointer to that risk rather than a defence against it, and the sponsorship request at the top of the page is about the project, not about the use.
For an ordinary user, this is not installable software in the usual sense. It requires a jailbreak, a package manager, a set of dependencies from three different authors, and a build for the right lane. The Settings app configuration is friendly, but everything underneath it is not.
The technical state is also worth noting. The release tags are v3.7.6 from 2023-05-30, v3.7.5 from 2023-05-21 and v3.7.4 from 2023-05-20, so the last tagged release is from 2023, while the last push was on 2026-10-19. The repository is not archived, so work has continued, but the gap between the last tag and the last commit means the tagged versions and the current source are not the same thing, and the compatibility table is describing package ranges rather than a specific published build.
For a researcher, the practical first step is to read the compatibility note rather than the version table, confirm the dependencies are present at the required versions, and build one lane at a time using the two commands the README gives.
Editorial conclusion
Shadow suits a security researcher who needs to run an app on a jailbroken device without the app noticing, and it suits someone maintaining per-app configuration across several jailbreak flavours. It is the wrong tool for an end user, since it requires a jailbreak, a package manager and a build of the tweak, and it is the wrong tool if you need a guaranteed result on a specific app, because the README states there is no guarantee every app and detection SDK works everywhere. Before installing it, read the compatibility note rather than the version table, because the table lists declared package ranges and not device-tested results, and check that the required dependencies are present, AltList, libSandy and HookKit 3.0.4 or newer.
Frequently asked questions
How do I install Shadow on iOS?
Add https://ios.jjolano.me to your package manager and install me.jjolano.shadow, or grab the latest release from GitHub. It needs AltList and libSandy from opa334, HookKit 3.0.4 or newer, and Injection Foundation is recommended.
How do I configure Shadow?
Open the Settings app and go to the Shadow pane, where you can set global defaults or a per-app configuration. The shdw command line tool is included, and shdw -d keeps the app ruleset in sync.
Which iOS versions and jailbreak types does Shadow support?
The compatibility table lists rootful legacy on iOS 9 to 13, rootful modern on 14 and later, rootless on 15 and later, and RootHide on 15 to 17, with the architecture for each. The README states these are declared package ranges rather than a device-tested version matrix.
How do I build Shadow from source?
It requires Theos. Build one lane at a time, running .github/scripts/build-deps.sh followed by ./build.sh with the lane name, for example rootful-modern. The lanes are rootful-legacy, rootful-modern, rootless and roothide, and the tests run with make -C tests test.
What should I check if Shadow is not working?
The README suggests disabling other tweaks per-app with Choicy, downgrading the app rather than stacking multiple bypass tweaks, and testing in a stock jailed state on rootless or semi-untethered systems to isolate whether the issue is the tweak or the environment.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jjolano-shadow)Was this useful?