The Permission Slip Problem: How Software Learned to Rewire Other Software

· Hunter · 11 min

Modern software rarely stays in its lane. Over three decades, apps learned to extend browsers, hook into operating systems, watch files, launch at startup, and request tokens to act inside other systems.

In March 2019, Microsoft engineer Raymond Chen wrote about a small but revealing Windows limit: File Explorer can only show 15 icon overlays at a time. Fifteen. Dropbox, OneDrive, TortoiseSVN, and other apps all compete for those slots, so a sync app can work perfectly and still lose its checkmarks because something else claimed the space first.

That detail is funny for about 10 seconds. Then it becomes a map of how modern software actually works.

Your computer is full of programs that do not just run alongside one another. They add context-menu items, register to launch at login, watch folders for changes, intercept links, claim file types, ask for tokens to read your mail, and request permission to control other apps. The visible app window is often the least interesting part. The real action is in the hooks.

Software did not start this way. It learned.

Before the hooks, software mostly stayed put

Early personal computing had fewer moving parts and fewer expectations. A word processor processed words. A spreadsheet handled cells. Programs opened files and saved files. The operating system managed traffic, but the lanes were relatively clear.

The 1990s changed that. Windows 95 helped normalize the idea that media and software could trigger behavior automatically. AutoRun and AutoPlay made CDs feel magical: insert a disc, and something happened. That same convenience later turned into a security problem serious enough that Microsoft partially disabled USB AutoRun between 2009 and 2011 after worms such as Conficker abused it (Microsoft Security Advisory 967940).

Browsers were changing at the same time from document viewers into miniature operating systems. Internet Explorer 4, released in 1997, introduced Browser Helper Objects, or BHOs. A BHO was a COM DLL that Internet Explorer could load into its own process to modify behavior. Toolbars used them. Add-ons used them. Adware loved them. And because of how Windows was built, many BHOs could also load into Windows Explorer, so a browser add-on could affect the desktop shell itself (Wikipedia).

That was the shift. Software was no longer just an application. It could become a resident species inside another application’s habitat.

Microsoft also gave developers formal ways to extend the Windows shell. Context menu handlers, icon overlay handlers, preview handlers, thumbnail handlers: all of these let third-party code run inside Explorer (Microsoft Shell Extensions documentation). That is why right-click menus on old Windows machines can feel like archaeological sites. Every installed utility leaves behind a fossil.

By the 2000s, the machine had become a negotiation among software actors. Installers wrote themselves into startup locations such as the `Run` and `RunOnce` registry keys (Microsoft). Updaters stayed resident. Antivirus products inserted themselves deeply. Sync clients watched folders. Version-control tools painted overlays onto files. The prize was not just being installed. The prize was being ambient.

Consent arrived late

The first generation of these integrations was built on a large assumption: local software was trusted until proven otherwise.

That assumption aged badly.

Windows Vista introduced User Account Control to put a consent barrier in front of system-level changes (Microsoft). Apple followed with Gatekeeper and later expanded privacy controls through TCC, covering things like microphone, camera, files, and Apple Events automation.

The pattern is consistent across platforms. First, a capability is opened because it is useful. Then people build products on top of it. Then abuse appears. Then the permission prompt arrives, slightly out of breath.

The web went through the same cycle. OAuth 2.0 became RFC 6749 in 2012. Its core idea was simple: let an app obtain limited access to a service without taking the user’s password (RFC 6749). Instead of handing a calendar app your Gmail password, you approve scopes on a consent screen.

This was the permission slip made formal.

On mobile, Android’s runtime permissions moved many requests from install time to the moment of use in 2015 (Android Developers Blog). iOS built deep linking through custom URL schemes and Universal Links while warning developers that these routes can become attack surfaces if inputs are not validated (Apple).

The modern operating system is less a stack of isolated apps than a treaty system. Every useful feature is also a border crossing.

How the rewiring works

There is no single master mechanism. There are several families of hooks.

The oldest is in-process extension.

A shell extension or BHO works by loading someone else’s code into a host process. That makes the integration fast and powerful. It also means a crash, leak, or malicious behavior can spill directly into the host. Explorer becomes the meeting room and the hostage.

That is how a version-control client adds “Commit” to your right-click menu. Explorer asks the extension what it wants to contribute for this file type, and then invokes third-party code when you click. The same pattern powers preview panes, thumbnail handlers, and icon overlays.

The overlay limit is a perfect example of hidden infrastructure shaping visible behavior. Windows reserves only 15 overlay slots, and some are effectively reserved by the system. So vendors race for priority, creating an accidental scarcity economy inside your file manager (Microsoft legacy docs, Raymond Chen).

The second family is autostart and persistence.

Programs register themselves in startup folders, `Run` keys, scheduled tasks, services, LaunchAgents, and LaunchDaemons. On macOS, `launchd`, introduced in 2005, became the central manager for background jobs (Apple launchd docs). Some of this is benign plumbing: update checkers, sync clients, backup tools. Some of it is the exact same persistence model used by intruders.

The third family is delegation.

OAuth is the cleanest example. An app asks a trusted identity provider for a token, the user sees a consent screen listing scopes, and the app receives permission to do specific things. Calendar assistants, CRM plugins, browser tools, AI assistants, and code integrations often work this way. Tokens are now operational inventory, which is why fast revocation matters during incidents.

The fourth family is inter-app routing.

Android intents let one app declare that it can handle a certain action or content type (Android Intent docs). iOS uses custom URL schemes and Universal Links for similar handoffs. Tap a map link in one app, land in another. It feels seamless because the operating system acts as a switchboard.

The fifth family is automation.

Accessibility and testing frameworks opened a door that software companies increasingly want to walk through. Windows UI Automation and macOS Apple Events can let one app inspect or control another app’s interface. On macOS, this now triggers TCC prompts for controlling other apps.

The sixth family is filesystem watching.

APIs like Windows `ReadDirectoryChangesW`, macOS FSEvents, and Linux inotify let software watch directories and react when something changes. That is how sync clients, backup systems, developer tools, and media indexers feel instant. The file becomes a trigger.

The attack surface is the feature surface

The easy story is that all of this happened because software companies got greedy or sloppy. Sometimes they did. But that is not the whole story.

The harder truth is that many mechanisms associated with abuse are also the mechanisms that make modern computing pleasant.

The same shell extension model that produced junk toolbars also gave people TortoiseSVN’s right-click workflow. The same filesystem hooks that enable ransomware to react quickly also make Dropbox sync feel instant. The same accessibility permissions that can be abused for UI redressing are essential for screen readers and automation. The same OAuth delegation model that lets a bad extension siphon data also lets you connect a calendar app without surrendering your password.

Browser and OS vendors have spent the last decade narrowing these powers without breaking the useful parts. Chrome deprecated NPAPI plugins in 2014–2015 (Chromium Blog). Firefox removed the old XUL/XPCOM add-on model in 2017 in favor of WebExtensions. Chrome’s Manifest V3 rollout further constrained what extensions can do in the background (Chromium Blog).

The common misconception is that platforms are moving from open to closed. A better description is that they are moving from ambient, implicit power to narrower, declarative power. Old systems often let code do things because it was there. Newer systems prefer manifests, scopes, entitlements, prompts, and revocation.

The system wants every cross-boundary action to come with a receipt.

The evidence is all around us

Some of the clearest examples are concrete.

Lenovo’s Superfish scandal in 2014–2015 involved preinstalled adware that inserted a root certificate authority so it could intercept HTTPS traffic, effectively rewriting the browser’s trust model (CISA).

Then there are extensions. In 2019, the DataSpii investigation found that eight Chrome and Firefox extensions were exfiltrating sensitive browsing data from millions of users, including personal information and corporate documents (Security with Sam). Mozilla also removed Avast and AVG browser extensions that year for collecting more data than necessary (ZDNet). In 2021, Google forcibly disabled The Great Suspender after it was found to contain malware (9to5Google).

Mobile has its own versions. When iOS 14 added clipboard-access banners, users suddenly saw how often apps were reading the clipboard. TikTok, among others, was publicly caught polling it and promised to stop (MacRumors). The behavior existed before. Apple just put a light on it.

Permission prompts as border crossings
Permission prompts as border crossings

Academic work has also shown how dangerous combinations of benign-looking permissions can be. A 2017 IEEE Security & Privacy paper demonstrated that, with just `SYSTEM_ALERT_WINDOW` and `BIND_ACCESSIBILITY_SERVICE`, Android malware could achieve “complete control of the UI feedback loop,” enabling stealth phishing and installs (paper).

That is the recurring lesson of the permission slip problem: power accumulates compositionally. Each individual hook may look reasonable. The system-level picture can be wild.

Why this changes how the digital world looks

Once you start seeing software as a web of negotiated permissions rather than a pile of self-contained apps, ordinary computing becomes easier to decode.

A browser extension is not just a convenience add-on. It is a resident with a lease inside the browser. A cloud drive is not just a folder. It is a filesystem watcher, an overlay claimant, a background daemon, a network client, and often a login item. A chatbot connected to your documents is not just AI. It is an OAuth scope decision with a natural-language front end.

This also explains why platform fights over prompts, manifests, default apps, and background execution feel so bitter. They are not cosmetic UX debates. They are arguments over who gets to rewire whom, and under what paperwork.

The same tension is now showing up in AI-driven automation. If a system can read the screen, manipulate the browser, click buttons, and move data among services, it is replaying 30 years of software integration history in compressed form. The old question returns with new clothes: where is the boundary, and who signed the permission slip?

The answer has never been nowhere. Modern computing works because boundaries are porous. The real story is that we spent decades building tunnels first and guardrails later.

FAQ

When did software first start crossing app boundaries in a serious way?

The 1990s were the turning point. Windows 95 normalized automatic behavior through AutoRun and AutoPlay. Internet Explorer 4 introduced Browser Helper Objects in 1997, and shell extensions let third-party code run inside Windows Explorer.

Why did people tolerate this for so long?

Because much of it was genuinely useful. Right-click version control, instant file sync, browser password managers, and single sign-on all depend on some form of cross-app integration. The convenience arrived before the threat model matured.

Why are permission prompts still so bad at explaining risk?

Because the real risk is often combinatorial. “Allow this app to access your files” sounds simple. “Allow this app to watch your files, launch at startup, add a shell extension, and obtain a long-lived token to your cloud storage” is closer to reality.

Did browsers and operating systems actually get stricter?

Yes, in specific ways. Chrome killed NPAPI and is enforcing Manifest V3. Firefox moved to WebExtensions. Android shifted to runtime permissions. macOS expanded TCC. Windows hardened default-app handling. The direction is toward narrower, more inspectable privileges.

Is cross-app control always a security smell?

No. Accessibility software, testing tools, automation frameworks, sync clients, backup systems, and delegated logins all rely on it. The problem is not that apps can interact. The problem is that useful interaction and invasive control often use the same plumbing.

---

<sub>8cf885dd</sub>