# EvilAppleJuice-ESP32: the fork that turned an iPhone prank into a denial of service

> A C++ ESP32 firmware that floods BLE proximity advertisements, forked from AppleJuice and pushed further with randomised MACs, randomised advertisement types and 9 dBm transmit power.

**ckcr4lyf/EvilAppleJuice-ESP32** — Spam Apple Proximity Messages via an ESP32

- Repository: https://github.com/ckcr4lyf/EvilAppleJuice-ESP32
- Stars: 2,330 · Forks: 221
- Language: C++
- License: WTFPL
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/ckcr4lyf-evilapplejuice-esp32

## What it actually does to an iPhone

The repository description is two words: spam Apple Proximity Messages. BLE proximity messages are the advertisements iOS devices listen for to detect things like AirPods, shared photo streams and nearby devices, and iOS pops a notification when one matches something it recognises. EvilAppleJuice-ESP32 sends those advertisements continuously, and the README's claim about what happens next is blunt: with the randomisation optimisations, a single ESP32 can render an iPhone almost useless, with a new notification appearing as soon as the previous one is dismissed. The result is not a single fake pop-up but a loop, because every advertisement triggers another one. The README is clear that this is a proof of concept about Apple's behaviour rather than an exploitation tool, and it frames the whole project as a demonstration that a fifteen dollar board can drive an operating system into a notification loop. It is also, unavoidably, a prank tool, and the repository carries the tag accordingly: it is not filed under security research tooling with a responsible disclosure process attached.

## The fork from AppleJuice and what it added

The lineage matters, because the diff between this project and its ancestor is where all the interest is. EvilAppleJuice-ESP32 is based on work by ronaldstoner in the AppleJuice repository, specifically the ESP32 Arduino sketch, and it credits simondankelmann for the discovery of additional advertising messages that pop new notifications on iOS devices. The README lists four changes this implementation makes on top of that base, and they are all in the same direction. It uses a random source MAC address, including the `BLE_ADDR_TYPE_RANDOM` flag rather than a public address. It randomly picks the BLE advertisement type, which the README links to a pull request on the upstream repository with a note that this may lead to more success. It randomly picks one of the possible emulated devices on every cycle. And it sets ESP32 BLE transmit power to the maximum 9 dBm to increase range. Every one of those choices attacks the same weak point. Apple's deduplication logic almost certainly keys on something about the advertisement, and varying every field it could plausibly key on makes each one look like a different device arriving, which is exactly the behaviour needed to keep the notification queue from collapsing into a single entry.

## The arithmetic of 87 possible advertisements

The README does the arithmetic explicitly, and it is worth doing along with it because it explains why the effect is so persistent. There are 29 emulated devices and 3 advertisement types, giving 87 unique possible advertisements, ignoring the random source MAC entirely. One of those 87 is broadcast every second by default, and because the choices are remade on every run rather than once at boot, the sequence does not repeat over any interval a deduplication heuristic would be willing to wait out. Add the randomised MAC and the effective space is far larger than 87. This is the single most important line of reasoning in the project, because it explains why the original AppleJuice sketch is a curiosity and this one is a nuisance. A fixed advertisement gets filtered. A rotating set of 87 that never repeats does not, because identifying it as a duplicate requires having seen it before. The 9 dBm power setting extends the range over which the attempt happens, which matters because BLE range is short enough that physical proximity is otherwise a real constraint on where you can stand.

## What the README confirms, and where it stops

The project records its own test matrix, which is more useful than it first appears because the range of results defines the boundary of the technique. It confirms notifications on iPhone 15 running iOS 17.1.2, iPhone 14 Pro Max on iOS 17.2, iPhone 14 Pro on iOS 16.6.1, iPhone 13 Pro on iOS 17.4, iPhone 11 on iOS 16.6.1, and iPad Pro 11 on iPadOS 17.3. The iPhone X on iOS 14.8 is listed as working but only for five notification types: AppleTV Keyboard, TV Color Balance, AppleTV Setup, AppleTV Homekit Setup and AppleTV New User, which suggests older iOS has a much smaller set of triggers rather than a different mechanism. Below that, iPhone 4S on iOS 10.3 does not work at all. The README also records two observations that are easy to miss and useful in practice: notifications do not appear if the Keyboard is open, and they do not appear if the Camera is open. Those two carve-outs are effectively workarounds, since a user who suspects the cause can leave a keyboard up. The most recent commit is dated 2026-06-06, so the project is still being worked on.

## Flashing it with the Arduino CLI on Linux

The README recommends PlatformIO with VS Code, and notes the project has been tested on an ESP32-C3 from AirM2M. It also documents an Arduino CLI path for people without that setup, and the Linux example is the more useful of the two because it names a real board identifier and a real port. On Linux the ESP32-C3 enumerates as `/dev/ttyACM0`, and the serial port needs to be made writable by the user first:

```
sudo chmod 666 /dev/ttyACM0
```

The board identifier matters as much as the port, so the compile, upload and monitor are chained in one command with the AirM2M ESP32C3 fqbn:

```
arduino-cli compile --fqbn esp32:esp32:AirM2M_CORE_ESP32C3 EvilAppleJuice-ESP32-INO -v && \
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:AirM2M_CORE_ESP32C3 EvilAppleJuice-ESP32-INO -v && \
arduino-cli monitor -c baudrate=115200 -p /dev/ttyACM0
```

The `EvilAppleJuice-ESP32-INO` argument is a sketch directory, which is the whole sketch rather than a source file, and the Windows version of the same commands uses `COM4` as the port and `esp32:esp32:esp32c6` as the fqbn instead. The README is explicit that the port and board should be replaced with whatever yours actually are. Monitor runs at 115200 baud. Note that `chmod 666` on the serial device is a wide permission grant and is only appropriate on a machine you control; a udev rule or a group membership is the tidier way to get the same result.

## Why the tree has two copies of the firmware

The repository tree is small enough to read at a glance: `.gitignore`, `LICENSE`, `README.md`, `platformio.ini`, three source directories named `src`, `include` and `lib`, a `test` directory, and one unusual entry, `EvilAppleJuice-ESP32-INO`. The README explains what that directory is. The project was originally developed for PlatformIO with VS Code, and Arduino support arrived because people asked for it. The Arduino version was achieved by copying the `main.cpp` file as `EvilAppleJuice-ESP32-INO.ino` and putting it in its own folder, with the other `.hpp` and `.cpp` files copied as is. That is a duplication rather than an abstraction, and it means the two build paths can drift: a fix applied to the PlatformIO source does not automatically reach the Arduino sketch, and the README does not describe a process for keeping them in sync. The licence is the WTFPL, and the project carries 2,291 stars, 218 forks and 6 open issues on the default branch, master, with no tagged releases at all, so there is no version history to consult and no upgrade path to follow. Everything interesting about this project is in the README and in the four-line differences from its ancestor.

## Conclusion

What makes this firmware interesting is not that it can pop a notification on an iPhone, which the original AppleJuice sketch already did, but that it stopped caring about looking like one device. Randomising the source MAC, the advertisement type and the emulated device turns a cosmetic spoof into a denial of service against the notification stack, and the README's own claim that a single ESP32 can render an iPhone almost useless follows directly from those four lines of change. The hardware bill is one ESP32-C3 and a USB cable. The cost is that anyone near one has to disable Bluetooth in Settings rather than in Control Centre, and the project's own unanswered Apple forum thread from over a year ago is the clearest statement of where that leaves things.

## FAQ

### How do I flash EvilAppleJuice-ESP32 to my board?

The README recommends PlatformIO with VS Code, or the Arduino CLI from the project root. On Linux the board shows up as /dev/ttyACM0 and needs the serial port made writable with sudo chmod 666 /dev/ttyACM0, then arduino-cli compile, upload and monitor run against the AirM2M ESP32C3 fqbn.

### Which iPhones and iOS versions are confirmed to work?

The README lists iPhone 15 on iOS 17.1.2, iPhone 14 Pro Max on 17.2, iPhone 14 Pro on 16.6.1, iPhone 13 Pro on 17.4, iPhone 11 on 16.6.1 and iPad Pro 11 on iPadOS 17.3. An iPhone X on iOS 14.8 works but only triggers five AppleTV-related notification types, and an iPhone 4S on iOS 10.3 does not work.

### What makes this different from the original AppleJuice sketch?

Four changes: a random source MAC address including BLE_ADDR_TYPE_RANDOM, a randomly chosen BLE advertisement type, a randomly chosen emulated device on every cycle, and maximum 9 dBm transmit power. With 29 devices and 3 advertisement types that is 87 distinct advertisements before the MAC is counted, and one is sent every second.

## Sources

- [ckcr4lyf/EvilAppleJuice-ESP32 on GitHub](https://github.com/ckcr4lyf/EvilAppleJuice-ESP32)
- [Issues](https://github.com/ckcr4lyf/EvilAppleJuice-ESP32/issues)
- [License: WTFPL](https://github.com/ckcr4lyf/EvilAppleJuice-ESP32/blob/master/LICENSE)
- [README](https://github.com/ckcr4lyf/EvilAppleJuice-ESP32/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ckcr4lyf-evilapplejuice-esp32
