Auditing AI Agent Tool Execution on macOS After the Meta Muse Zero-Day

Auditing AI Agent Tool Execution on macOS After the Meta Muse Zero-Day

pr0h0
ai-agent-securitymacoszero-daysandboxingmalware-injection
AI Usage (90%)

Why the Meta Muse hijack was a tool-execution problem, not a chat bug

On September 22, 2026, four outlets reported that Meta's Muse AI agent could be hijacked and used to inject malware, and that Mac app users were hit before Meta patched it. Most of that coverage treats the story as AI safety. I think that framing buries the actual lesson.

A chatbot that says something wrong is a content problem. An agent with a file-system API, network access, and an AppleEvents grant is a program running with your privileges. Steer that program and you haven't "jailbroken a model" — you've executed through a tool the user already trusted. This post walks through the audit I run on an agent's macOS footprint — entitlements, TCC grants, tool scopes, signed tool calls, and update channels — so you can check the execution path before the next hijack lands. Unlike the model's internal reasoning, all of that is observable right now.

What the public record on the Meta Muse zero-day actually says

What the September 22, 2026 reports confirm

  • CyberSecurityNews, Tech Times, The Verge, and iPhone in Canada all published on September 22, 2026; source timestamps span 02:10 to 17:24 UTC.
  • All four describe a zero-day in Meta's Muse AI agent that let attackers hijack the tool and inject malware.
  • The affected surface described is the Muse Mac desktop app.
  • The Verge reported that Meta patched the exploit, describing it as one that let attackers control the AI agent.
  • Tech Times frames the flaw against Muse's privacy-and-security marketing.

What is still unknown about the Muse zero-day

My material names no CVE identifier, no affected version range, no technical write-up, and no researcher attribution. Also unknown: which component was abused — prompt handling, tool dispatch, or the update path; whether exploitation needed local access or user interaction; and how the malware was actually delivered.

No vendor security bulletin was public in the sources I reviewed, so treat any claim about the exact mechanism as unverified until Meta or the reporting researchers publish details. That gap matters, because "inject malware" reads to most people as "the model was tricked." My inference — not a confirmed fact — is that tool execution was the delivery channel. It's the pattern that best explains malware landing from an agent that already held the user's permissions.

The real trust boundary is agent tool execution, not the model

Every agent stack has roughly three layers: the model, the planner that turns model output into tool calls, and the executor that runs them. Prompt injection is a bug in layer one. It becomes an incident in layer three. If you are auditing an agent on macOS, audit the executor.

The macOS capability ladder: TCC grants, entitlements, and helper processes

What an agent can touch is decided by three things, and they escalate in a predictable order:

  • Sandboxed app with user-selected file access — the marketing version of the agent. Files arrive through a picker, access is per-file.
  • Sandboxed app with security-scoped bookmarks — persistent read/write to folders the user approved once. Grants quietly outlive the session.
  • Non-sandboxed app — full user-level file access, subject to TCC prompts. One "Allow" click and it's permanent for that bundle ID.
  • Widening entitlementscom.apple.security.temporary-exception.files.home-relative-path.read-write, com.apple.security.cs.disable-library-validation, allow-dyld-environment-variables. Each one undercuts the sandbox you thought you had.
  • AppleEvents and Accessibility — the agent can drive Finder, Terminal, System Events, or Mail. This is the rung where a hijacked agent stops needing its own privileges.
  • A privileged helper or launchd job — root-adjacent persistence and access to anything TCC won't even prompt for.

Why "the agent only reads files" is rarely true in practice

Reading is enough. An agent with read access to ~/.ssh, browser profile directories, or ~/.aws plus outbound network access can exfiltrate without writing a byte. And the "read-only" claim usually breaks one layer down anyway: agents write caches, drafts, transcript logs, and tool config files. On macOS, ~/Library/Application Support/<bundle-id>/ is the one to watch, because that's where an app often loads its own tool definitions and prompt files from on the next launch. For a sandboxed agent, a write there is a persistence primitive, not a cache — and it is the first place I look after a suspected hijack.

Auditing an AI agent's macOS footprint before someone else hijacks it

Here's the audit I run. Substitute your own bundle path; I use /Applications/Muse.app as the placeholder.

Step 1 — enumerate the agent app's entitlements and code signature

entitlements-audit.sh
APP=/Applications/Muse.app

codesign -dv --verbose=4 "$APP" 2>&1 | grep -E "Identifier|TeamIdentifier|Authority|^flags|CDHash"

codesign -d --entitlements :- "$APP" 2>/dev/null

The exact values are yours, but the field names below are what you're reading. Annotated example of the shape of the output:

Identifier=<bundle-id>
TeamIdentifier=<10-char-team-id>
Authority=Developer ID Application: <name> (<team-id>)
flags=0x10000(runtime)
CDHash=<hash>

[Key] com.apple.security.app-sandbox => true
[Key] com.apple.security.network.client => true
[Key] com.apple.security.files.user-selected.read-write => true
[Key] com.apple.security.automation.apple-events => true

The things I flag immediately: a missing app-sandbox; any temporary-exception reaching into the home directory; disable-library-validation or allow-dyld-environment-variables; and automation.apple-events. Check the nested binaries too — find "$APP" -type f -perm -111, then codesign -dv on each. A helper with a different Team ID, an ad-hoc signature, or a linker-signed marker is a finding on its own.

Step 2 — read the TCC database for what the agent was actually granted

sqlite3 "$HOME/Library/Application Support/com.apple.TCC/TCC.db" \
  "select service, client, auth_value, auth_reason, last_modified \
   from access order by last_modified desc limit 20;"
⚠️

Reading the user TCC database requires Full Disk Access for the terminal you run it from. If sqlite3 returns "unable to open database file," that grant is missing — not that the file does not exist.

auth_value is 0 for denied, 2 for allowed, 3 for limited. The services that should make you stop and think: kTCCServiceSystemPolicyAllFiles, kTCCServiceAccessibility, kTCCServiceScreenCapture, and kTCCServiceAppleEvents where the indirect target is com.apple.systemevents, com.apple.Terminal, or com.apple.finder. An AppleEvents grant to System Events is functionally "run anything." These survive app updates as long as the bundle ID and signing identity stay stable, so a hijack inherits them silently.

Step 3 — find tool binaries that can write outside the sandbox

for b in $(find "$APP" -type f -perm -111); do
  printf '%s\t' "$b"
  codesign -d --entitlements :- "$b" 2>/dev/null | grep -c 'app-sandbox'
done

Binaries that report 0 have no sandbox entitlement of their own. That's a lead, not a verdict: an XPC service carrying com.apple.security.inherit picks up the parent's sandbox, which is the safe pattern. A helper with no sandbox entitlement and no inherit is the one that runs wide open.

💪

While you are in the app container, grep the tool configuration for command, exec, url, and shell. If a remote config can add a new executable path, you have found an injection surface no prompt filter will ever see.

Step 4 — watch what the agent does at runtime, not what it claims

log stream --style compact --predicate \
  'process == "Muse" OR (subsystem == "com.apple.TCC" AND eventMessage CONTAINS "Muse")'

sudo fs_usage -w -f filesys Muse

launchctl print gui/$UID | grep -i -A3 muse
ls -la ~/Library/LaunchAgents /Library/LaunchDaemons | grep -i muse

Three things to look for: writes outside the container, exec of /bin/sh, osascript, or curl, and connections to hosts the app doesn't document. Structured Endpoint Security events via eslogger beat fs_usage — but whether eslogger works without an Apple-granted Endpoint Security entitlement varies by build, so verify it on your machine before you rely on it. I haven't confirmed that on every current macOS release.

Least-privilege tool scopes: risky versus safer grants

Tool capabilityBlast radius if hijackedTighter grant that still works
Read the whole home directorySSH keys, session cookies, cloud tokensApp-owned workspace directory via a security-scoped bookmark
Write anywhere the user can write~/Library/LaunchAgents, shell rc files, git hooksContainer only, plus explicit user-selected paths
AppleEvents to System Events or FinderEffectively arbitrary automationDrop the entitlement; use the app's own XPC surface
Accessibility / synthetic inputCan click through consent dialogsNever grant to an agent; require a human action
Unrestricted outbound networkSilent exfiltration of everything it readDeny by default, allowlist the model and tool API hosts
Remote tool or plugin configAdds new exec paths after installSigned manifests, pinned versions, no new exec paths

Signed tool calls: signing proves origin, not authorization

Signing tool calls is worth doing. The version most teams ship is theater, and it's worth being blunt about why.

Why an HMAC computed inside the client app is not a security control

If the client app computes the MAC, the key lives on the client, and the hijacked client is exactly the threat model. An attacker who steers the agent doesn't need to steal the key — they call the same signing function the app calls. The signature proves that some copy of the app produced the message. It proves nothing about whether the user authorized the action. Static API keys baked into the app share that property, and signing at the planner layer is worse, because the planner is the component you already decided is untrusted.

What a verifiable tool-call chain should look like

  • The authorization decision lives server-side, or in a local privileged daemon holding a key the agent process cannot read.
  • Per-tool scoped tokens, bound to the user session, short TTL, single-use nonce, audience restricted to the executor.
  • The decision is enforced at the executor, after arguments are fully resolved, so there's no time-of-check/time-of-use gap.
  • Deny by default. The agent proposes; the executor disposes.
  • Log the decision and a hash of the resolved arguments — never the raw prompt.

The update channel is the injection path nobody audits

Auto-update, plugin manifests, and remote tool configs as executable input

If the agent fetches a tool manifest, plugin definition, or system prompt from a URL, that URL is a code path. Sparkle-style updaters, plugin marketplaces, MCP server configs, and "skills" directories all fall in this category, and all get treated as content rather than code. The controls are boring and effective: verify signatures and notarization on update, keep the update signing key out of the app's reach, refuse remote config that can introduce a new executable path, pin and review manifest versions, and never let the agent write to its own tool config. That last one converts a chat feature into file-system persistence.

Detection: what to log when an agent-driven action fires

Emit one event per tool call, structured: timestamp, app bundle ID and CDHash, tool name, argument hash, resolved executable path, allow/deny decision, scope used, files written, destination hosts, parent PID. Ship it off-box. The macOS unified log is useful during investigation, but it isn't tamper-evident against an attacker who holds root — detective control, not audit trail.

What I would fix first, in order

  1. Remove the broad TCC grants — AppleEvents, Accessibility, and AllFiles. Highest blast radius, no code rewrite, reversible today.
  2. Move the authorization decision out of the client app. Every in-app signature check is decoration until this happens.
  3. Scope the tool layer and deny by default, especially write paths outside the container.
  4. Instrument tool execution and ship the events somewhere the agent cannot delete.
  5. Then invest in prompt-injection filtering. It's the last layer, not the first.

What I confirmed versus what I did not test

Confirmed: the four publishers reported on September 22, 2026; the reports describe a Muse agent that could be hijacked to inject malware on the Mac app; The Verge reported a patch. The codesign, sqlite3, log stream, and launchctl invocations above are the ones I run against local app bundles on current macOS, and the field names shown match what the OS returns.

Not tested: I have not tested Muse, its patched or unpatched builds, or the exploit itself. I could not verify which component was abused, how the malware was delivered, or whether a CVE was assigned. The eslogger entitlement behavior is untested on my side, and the mapping from agent hijack to malware delivery in this specific incident remains inference.

Further Reading

No Meta vendor security bulletin for this flaw was public in the material I reviewed at the time of writing.

Share this post

More posts

Comments