# How Magisk Denylist Bypasses System Integrity Checks for Specific Apps

> Learn how Magisk denylist bypasses system integrity checks by unmounting filesystems and blocking Zygisk injection for a clean app environment. Discover the tech behind Magisk.

- Repository: [John Wu/Magisk](https://github.com/topjohnwu/Magisk)
- Tags: internals
- Published: 2026-03-05

---

**Magisk's denylist bypasses system integrity checks by unmounting Magisk-specific filesystems and blocking Zygisk module injection for targeted processes, presenting a clean, unmodified environment to denied apps.**

The denylist feature in the [topjohnwu/Magisk](https://github.com/topjohnwu/Magisk) repository allows users to hide root access and modifications from specific banking, gaming, or enterprise apps. When an app is added to the denylist, Magisk orchestrates a multi-layered isolation mechanism that restores the original system state for that process alone, effectively cloaking its presence from runtime integrity checks.

## How the Magisk Denylist Works

The denylist operates through a coordinated sequence of flag setting, namespace manipulation, and injection prevention. When enforcement is active, every new process undergoes a check against the denylist database before Magisk applies its usual modifications.

According to the Magisk source code, the bypass mechanism relies on five core operations: marking the process as denied, enforcing global flags, reverting filesystem mounts, preventing module loading, and maintaining a clean execution environment.

## Flagging Denied Processes in Zygisk

When the Zygisk daemon spawns a new process, it calls `update_deny_flags()` in [[`native/src/core/deny/utils.cpp`](https://github.com/topjohnwu/Magisk/blob/main/native/src/core/deny/utils.cpp)](https://github.com/topjohnwu/Magisk/blob/master/native/src/core/deny/utils.cpp#L433-L440) to determine if the app should be isolated. This function checks the process name and UID against the SQLite denylist database.

If the process matches an entry, Magisk sets two critical bitmask flags defined in [[`native/src/core/lib.rs`](https://github.com/topjohnwu/Magisk/blob/main/native/src/core/lib.rs)](https://github.com/topjohnwu/Magisk/blob/master/native/src/core/lib.rs#L121-L127):

```cpp
void update_deny_flags(int uid, rust::Str process, uint32_t &flags) {
    if (is_deny_target(uid, {process.begin(), process.end()})) {
        flags |= +ZygiskStateFlags::ProcessOnDenyList;
    }
    if (denylist_enforced) {
        flags |= +ZygiskStateFlags::DenyListEnforced;
    }
}

```

The `ProcessOnDenyList` flag identifies specific targets, while `DenyListEnforced` indicates the global enforcement state is active. These flags persist in the process's Zygisk state and dictate all subsequent isolation decisions.

## Enforcing the Denylist Globally

Before individual processes can be isolated, the denylist must be enabled globally. The `enable_deny()` function in [[`native/src/core/deny/utils.cpp`](https://github.com/topjohnwu/Magisk/blob/main/native/src/core/deny/utils.cpp)](https://github.com/topjohnwu/Magisk/blob/master/native/src/core/deny/utils.cpp#L52-L88) sets an atomic boolean flag that activates the enforcement mechanism system-wide:

```cpp
int enable_deny() {
    // ... mount-namespace validation ...
    denylist_enforced = true;  // Atomic flag activation
    
    // Terminate existing Zygisk-related processes on Android Q+
    kill_process("usap32", true);
    kill_process("usap64", true);
    return 0;
}

```

Once `denylist_enforced` is true, every subsequent mount namespace operation and process spawn undergoes denylist verification. This global switch ensures that newly added apps to the denylist are immediately protected without requiring a full system reboot.

## Reverting Magisk Mounts for Targeted Apps

The most critical step in bypassing integrity checks occurs in [[`native/src/core/mount.rs`](https://github.com/topjohnwu/Magisk/blob/main/native/src/core/mount.rs)](https://github.com/topjohnwu/Magisk/blob/master/native/src/core/mount.rs#L31-L70). When a process is flagged as `ProcessOnDenyList`, the Zygisk daemon triggers `revert_unmount()` to strip away all Magisk-related filesystem modifications:

```rust
pub fn revert_unmount(pid: i32) {
    // Switch to the target process's mount namespace
    if pid > 0 && switch_mnt_ns(pid) != 0 { return; }
    
    // Parse mount table and remove Magisk artifacts
    for info in parse_mount_info("self") {
        if info.source == "magisk" || info.root.starts_with("/adb/modules") {
            // Unmount Magisk tmpfs and module directories
            target.unmount().ok();
        }
    }
}

```

This function enters the target process's mount namespace and unmounts the Magisk temporary filesystem and any active module directories. By restoring the original mount namespace, apps like Google Pay or Pokémon GO see only the stock Android environment, causing SafetyNet and Play Integrity API checks to pass.

## Blocking Zygisk Module Injection

Even with clean mounts, Magisk must prevent its native hooks from loading into the denied process. After `update_deny_flags()` sets the isolation flags, the Zygisk daemon checks these flags before loading any modules. The system uses a `UNMOUNT_MASK` to detect denylist status and skips injection entirely when the mask matches.

This prevents root access callbacks, SELinux bypass hooks, and module code from entering the process address space. Consequently, integrity checks that scan for hooked system calls or modified SELinux contexts find no evidence of tampering.

## Configuring the Magisk Denylist via CLI

Users interact with the denylist through the Magisk command-line interface defined in [[`native/src/core/deny/cli.cpp`](https://github.com/topjohnwu/Magisk/blob/main/native/src/core/deny/cli.cpp)](https://github.com/topjohnwu/Magisk/blob/master/native/src/core/deny/cli.cpp). The following commands demonstrate how to add apps and enable enforcement:

```bash

# Add all processes of a banking app to the denylist

magisk --denylist add com.example.banking

# Verify the entry was stored in the denylist database

magisk --denylist ls

# Enable global enforcement (triggers enable_deny())

magisk --denylist enable

# Immediately kill existing app processes to apply isolation

magisk --denylist exec killall com.example.banking

```

The `add_hide_set()` function (called by the CLI) stores entries in an SQLite database. If enforcement is already active, it immediately kills matching processes using `kill_process()` to ensure the app restarts with the clean environment.

## Summary

- **Process Flagging**: The `update_deny_flags()` function in [`native/src/core/deny/utils.cpp`](https://github.com/topjohnwu/Magisk/blob/main/native/src/core/deny/utils.cpp) sets `ProcessOnDenyList` and `DenyListEnforced` flags for target UIDs.
- **Global Enforcement**: The atomic `denylist_enforced` flag activates system-wide checking when `enable_deny()` is called.
- **Mount Reversion**: `revert_unmount()` in [`native/src/core/mount.rs`](https://github.com/topjohnwu/Magisk/blob/main/native/src/core/mount.rs) removes Magisk tmpfs and module mounts from the denied process's namespace.
- **Injection Prevention**: Zygisk skips module loading for flagged processes, preventing root hooks from entering the process.
- **Clean Environment**: The combination of unmodified mounts and no injected code allows apps to pass system integrity checks like Play Integrity API.

## Frequently Asked Questions

### What is the difference between Magisk Denylist and the old MagiskHide?

The Magisk denylist is the successor to MagiskHide, implementing the same core concept through the Zygisk framework. While MagiskHide operated as a standalone hiding mechanism, the denylist integrates deeply with Zygisk's process spawning and mount namespace management, offering more reliable isolation by unmounting entire filesystem trees rather than just hiding specific files.

### Can apps still detect Magisk when using the denylist?

Properly configured, the denylist makes Magisk virtually undetectable to standard integrity checks. However, sophisticated apps may employ heuristics based on indirect artifacts (like modified kernel parameters or specific hardware fingerprints) that the denylist does not address. For maximum stealth, users should also ensure Magisk is installed with the "Zygisk" option enabled and no conflicting modules are active.

### How do I add an app to the Magisk denylist?

Open the Magisk Manager application, navigate to **Settings**, enable **Zygisk**, and toggle **Enforce Denylist**. Then select **Configure Denylist** and check the specific apps you want to hide Magisk from. Alternatively, use the CLI command `magisk --denylist add <package.name>` followed by `magisk --denylist enable` as implemented in [`native/src/core/deny/cli.cpp`](https://github.com/topjohnwu/Magisk/blob/main/native/src/core/deny/cli.cpp).

### Does using the denylist impact system performance?

The performance impact is negligible. The denylist adds a single hash lookup during process spawn (in `update_deny_flags`) and mount table parsing only for denied processes (in `revert_unmount`). Since most processes are not on the denylist, the atomic flag check has minimal overhead. Only denied apps experience the slight latency of namespace unmounting during their initial launch.