dontallow auto-denies the macOS Local Network permission prompt

dontallow auto-denies the macOS Local Network permission prompt

dontallow is a small open-source (MIT) launchd agent for macOS that automatically dismisses the prompt "Allow [app] to find devices on local networks?" by pressing Don't Allow, within a fraction of a second, every time it appears. According to its README, it uses no CPU while idle, survives reboots, and consists of two short Swift files with no dependencies.

The README explains the problem it targets. macOS Sequoia and later show the prompt the first time an app touches the local network. The decision is supposed to be remembered, but for many apps it is not, so the prompt returns on every launch, often for apps the user is not even using. Chromium browsers (Chrome, Brave, Edge, Island, Arc) copy their own app bundle into a random temp folder at launch so the code signature survives in-place updates. macOS keys the Local Network decision to that random path, so each launch looks like a brand-new app, and the Privacy settings fill up with duplicate "Google Chrome.app" rows that point at nothing. Apps with versioned install paths (anything installing into .../versions/1.2.3/) get a new row per update. Some prompts are also misattributed: macOS pins the dialog on whichever app it deems responsible, so prompts can appear for apps that are not running. The README adds that there is no supported way to prune the list, no MDM payload to pre-deny the permission, and tccutil reset does not cover it.

Some apps do legitimately need the permission: Chromecast and AirPlay discovery in browsers and media players, LAN multiplayer in games, and printer and scanner utilities. For those, the README says to answer Allow, and the answer is remembered as long as the app's path is stable.

Installation is through Homebrew (brew install johncassil/tap/dontallow) or make && make install. Running dontallow install writes a per-user launchd agent, starts it, and opens System Settings > Privacy & Security > Accessibility, because Accessibility is the permission that lets the agent press the button. dontallow status repeats the instructions if the grant is missing. Each dismissal posts a notification naming the app and the pause command; that notification can be muted in System Settings.

There are three ways to let an app through. One: dontallow pause 10m, then launch the app and click Allow yourself. Two: add the app's name to ~/.config/dontallow/allowlist (one per line, case-insensitive substring), and prompts for it are never touched. Three: flip the toggle in System Settings > Privacy & Security > Local Network; a dismissed prompt records a deny, which can be reversed there. A file at ~/.config/dontallow/grace sets a number of seconds to wait before the agent acts, giving the user a window to click Allow first (default 0.25).

The mechanism, as the README describes it: the prompt is a window owned by the system process UserNotificationCenter. The agent registers an Accessibility observer for window creation on that process and sleeps until one fires. It reads the dialog text, confirms it is a local network prompt, checks the pause setting and allowlist, and performs the Accessibility press action on the Don't Allow button. If the press is refused, it falls back to a synthetic click at the button's location. The README states it never modifies system files, never disables protections, and never chooses Allow.

For managed fleets, Local Network cannot be pre-set by MDM but Accessibility can. The README suggests building once, signing with a Developer ID, shipping the binary plus a PPPC profile granting Accessibility to its code requirement, and running dontallow install per user. One rough edge: macOS keys the Accessibility grant to the binary's code signature, and every build, including brew upgrade, produces a new one. After an upgrade, if dontallow status says the grant is missing, the user removes the dontallow row in Accessibility settings and adds it back from the printed path; the agent re-attaches on its own within ten seconds. A future release signed with a Developer ID is meant to remove this step.

On testing and compatibility: unit tests (make test) cover pure logic such as dialog text parsing, duration and pause parsing, allowlist matching, launchd plist generation and the Local Network rule decoder against a fixture archive. The end-to-end path can only be checked on a Mac with Accessibility granted. It builds with Apple's Command Line Tools alone, no Xcode, and needs macOS 13 or later to build, though the prompt itself exists only on macOS 15 Sequoia and later. Tested so far: Intel, macOS 26.6, with reports from other versions welcome. It works on English-localized macOS only for now, since the matcher keys on the dialog text and the Don't Allow button title; localized strings are planned.

Key facts

  • dontallow is an MIT-licensed macOS launchd agent that presses Don't Allow on the Local Network permission prompt within a fraction of a second, via the Accessibility API.
  • The README says macOS often fails to remember the decision: Chromium browsers copy their bundle to a random temp path at each launch, so every launch looks like a new app and duplicate rows pile up in Privacy settings.
  • Apps that legitimately need the permission can be let through with dontallow pause (for example 10m), an allowlist file of app names, or the Local Network toggle in System Settings.
  • Tested so far only on Intel with macOS 26.6; English-localized macOS only; the Accessibility grant may need re-adding after each brew upgrade until a Developer ID-signed release ships.

Why it matters

The Local Network prompt is meant to be answered once. According to the README, for many apps macOS does not remember the answer, so the dialog returns on every launch, sometimes for apps that are not running, and there is no supported way to prune the list, no MDM payload to pre-deny the permission, and tccutil reset does not cover it. dontallow is a stopgap for that gap: it answers "no" automatically instead of waiting for Apple to fix how the decision is stored.

Who it affects

Mac users on macOS 15 Sequoia and later who see the prompt repeatedly, especially those running Chromium browsers (Chrome, Brave, Edge, Island, Arc) whose per-launch bundle copy makes macOS treat each launch as a new app. It also touches people with versioned install paths, who get a new row per update. The README includes a fleet recipe for administrators: build once, sign with a Developer ID, ship the binary with a PPPC profile granting Accessibility, then run dontallow install per user.

How to use it

Install with brew install johncassil/tap/dontallow, or make && make install, then run dontallow install. It writes a per-user launchd agent and opens the Accessibility settings pane so you can grant the permission that lets it press the button. To let a legitimate app through (Chromecast or AirPlay discovery, LAN games, printer or scanner utilities), use dontallow pause 10m and click Allow yourself, add the app name to ~/.config/dontallow/allowlist, or flip the toggle under Privacy & Security > Local Network. A grace file sets a delay before the agent acts (default 0.25 seconds). The project is MIT licensed and builds with Command Line Tools alone.

How solid is it

The source is the project README, so the claims about behavior and macOS internals are the project's own. Unit tests cover the pure logic only; the end-to-end path (a real prompt, a real press) can only be verified on a Mac with Accessibility granted, with a manual recipe in Tests/INTEGRATION.md. The tested configuration so far is Intel with macOS 26.6, and reports from other versions are invited. The code is two short Swift files with no dependencies, which keeps it easy to read.

Risks and caveats

Each build produces a new code signature, and macOS keys the Accessibility grant to it, so after a brew upgrade the grant may need to be removed and re-added until a Developer ID-signed release arrives. The matcher works on English-localized macOS only. A dismissed prompt records a deny, so an app you later want to allow needs the Local Network toggle flipped in System Settings. Because the agent answers automatically, an app you do want to use needs a pause or an allowlist entry first. The tool needs the Accessibility permission, which the README says is what lets it press the button; it states the agent never modifies system files, never disables protections, and never chooses Allow.

“It never modifies system files, never disables protections, and never chooses Allow.”

— dontallow README