Skip to content

Investigating TCC Permission Abuse on macOS

How attackers abuse macOS TCC permissions, what each technique leaves in TCC.db, and how to pivot to unified logs, launchd, quarantine and shell history.

Published on 8 min read

TL;DR. Attackers on macOS need TCC permissions for most of what they want: Full Disk Access to read user data, Accessibility, Screen Recording and Input Monitoring to watch and drive the session, and Automation of Finder or System Events to act as the user. Each path leaves a characteristic row in TCC.db: which client, which service, how it was decided, and when. This article maps the common techniques to what you will find, and to the artifacts to pivot to next. The examples come from the fictional FIN-MBP-03 sample in TCC Parser.

Keep perspective: nearly every row described below also occurs on clean Macs. A finding is a question to answer, not an answer.

The techniques and their traces

TechniqueWhat it looks like in TCC.dbWhere
Full Disk Access to a terminal or interpreterkTCCServiceSystemPolicyAllFiles, client com.apple.Terminal, /bin/bash, /usr/bin/osascript and similar, auth_value = 2System DB
Surveillance capabilitieskTCCServiceAccessibility, kTCCServiceScreenCapture, kTCCServiceListenEvent, kTCCServicePostEventSystem DB
Automation of Finder, System Events or TerminalkTCCServiceAppleEvents, target com.apple.finder, com.apple.systemevents, com.apple.TerminalPer-user DB
Path-based or ad-hoc clientsclient_type = 1, path in /tmp, /private/var/tmp, /Users/Shared, a hidden dot-folder or Downloads, csreq cdhash-onlyBoth
Folder and volume access for stagingkTCCServiceSystemPolicyDocumentsFolder, ...DesktopFolder, ...DownloadsFolder, ...RemovableVolumesPer-user DB
CleanupRows removed with tccutil reset, visible only in the WAL or older copiesBoth
Direct database editsRows with no matching tccd activity, odd reason codes or requirementsDepends on protections

"System DB" and "per-user DB" reflect where these services usually live; the split has moved between releases, so query both.

Full Disk Access to terminals and interpreters

The shortest path to user data is to get Full Disk Access for something that runs arbitrary commands. Permissions are usually attributed to the responsible app, so a grant to Terminal covers every script, binary and one-liner launched from it. Look for FDA held by com.apple.Terminal, third-party terminals, or path-based interpreters, and read auth_reason: a user-driven reason (commonly 2 user consent or 3 user set) means someone clicked.

In the sample, Full Disk Access to com.apple.Terminal was granted at 10:11:37 UTC, six minutes into the intrusion window.

Accessibility, Screen Recording, Input Monitoring

These are the surveillance and control services. Accessibility lets a program click and type in other apps, including approving dialogs; Screen Recording sees the screen; Input Monitoring observes keystrokes; Post Event injects input. Malware typically requests them from a helper binary, sometimes after getting the user to approve a convincing prompt.

A denied row is evidence too. In the sample, the helper /Users/dana.whitlock/Library/Caches/.sync/sync-helper was granted Accessibility at 10:19:05 and was denied Screen Recording at 10:24:40. The denial shows the request happened, even though it failed.

On Sequoia and later, check ~/Library/Group Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist: far-future reminder dates there indicate someone suppressed the periodic Screen Recording reminder.

Automation of Finder, System Events and Terminal

Apple Events automation lets one app send commands to another. Control of Finder means copying and moving files as the user; control of System Events means scripting UI and system actions; control of Terminal means running commands through an app that may hold Full Disk Access. These rows live in the user database, with the target in indirect_object_identifier and its code requirement in indirect_object_code_identity.

In the sample, Terminal was allowed to control System Events at 10:14:02 and Finder at 10:16:48, both in dana.whitlock's database.

Path-based and ad-hoc signed clients

Legitimate apps are almost always recorded by bundle ID with a requirement tied to Apple or a Team ID. A client recorded by absolute path (client_type 1) in a temporary, shared or hidden folder, with a csreq that is only a cdhash, is a small, unsigned or ad-hoc signed program that someone placed and ran. That describes plenty of developer tools too, so check the path, the file, and how it arrived. Details in decoding csreq code requirements.

Staging data: folders and removable volumes

Grants for Documents, Desktop, Downloads and removable volumes to a terminal or helper, within minutes of each other, sketch the collection phase. In the sample: Documents and Desktop for Terminal around 10:18, Downloads for the sync-helper at 10:21:44, and removable volumes for Terminal at 10:38:55, which the story ties to a USB volume named "EXFIL".

Cleanup with tccutil

An intruder who knows about TCC may remove grants on the way out with tccutil reset. The row disappears from the database, but earlier copies of its page can stay in TCC.db-wal or freed pages. In the sample, the helper's Accessibility grant is gone from the current state and recovered from the WAL; the story places the removal at 10:47:12 UTC. See recovering removed TCC grants from the WAL.

Direct edits of TCC.db

System Integrity Protection prevents modification of the system database, even by root. With SIP disabled, a root process can write to it directly. The per-user database is protected by TCC rather than SIP, and public research has shown ways to tamper with it in the past. Signs to check, with care: rows whose last_modified has no matching com.apple.TCC activity in the unified log, reason codes that do not fit how the grant should have been made, and missing or odd code requirements. Record the SIP status of the Mac (from csrutil status on a live system, or from your triage tool) in the case notes.

MDM and PPPC

A malicious or unexpected PPPC profile can pre-grant many services without a prompt. It cannot silently grant camera, microphone or Screen Recording. Rows with auth_reason commonly read as MDM policy (6), a policy_id, or an entry in MDMOverrides.plist should match a profile your MDM team recognizes. In the sample, com.example.edr.agent holds Full Disk Access from a PPPC profile, which is expected for an EDR agent.

Building the timeline

Put the rows in order and look at gaps and bursts. The sample, in UTC on 2026-09-14:

TimeDatabaseEvent
10:11:37SystemFull Disk Access allowed for Terminal
10:14:02dana.whitlockTerminal may control System Events
10:16:48dana.whitlockTerminal may control Finder
~10:18dana.whitlockDocuments and Desktop access for Terminal
10:19:05SystemAccessibility allowed for the path-based sync-helper
10:21:44dana.whitlockDownloads access for the sync-helper
10:24:40SystemScreen Recording denied for the sync-helper
10:38:55dana.whitlockRemovable-volume access for Terminal
10:47:12SystemAccessibility row for the sync-helper removed (WAL only)

In TCC Parser, Findings raises a burst of permission changes from 10:11:37 to 10:24:40, followed by a 14-minute gap before 10:38:55. A time range of 10:05 to 10:50 (the Use the sample's incident window button on the Findings tab) scopes every tab to the intrusion.

Where to pivot next

TCC.db tells you what was possible. Other artifacts tell you what happened:

QuestionArtifact
Who requested what, and which process was responsible?Unified log, subsystem == "com.apple.TCC"
How did the helper arrive?Quarantine events database, download history, file system timestamps
How does it persist?LaunchAgents and LaunchDaemons (~/Library/LaunchAgents, /Library/LaunchAgents, /Library/LaunchDaemons) and login items
What was run in Terminal?Shell history (~/.zsh_history, ~/.zsh_sessions/)
Was a permission changed and removed?EDR telemetry; Endpoint Security TCC modification events from macOS 15.4
What left the Mac?Browser history, removable-media evidence, network logs

In the sample story, those pivots find a quarantined download tools.zip from https://files.example/…, a fake LaunchAgent com.example.updater.plist, files staged in ~/Library/Caches/.sync/ and a visit to transfer.example. None of those are in TCC.db; they are what the TCC rows point you to.

A starting query for the unified log, on a collected log archive or a live system:

log show --info --predicate 'subsystem == "com.apple.TCC"' \
  --start "2026-09-14 10:00:00" --end "2026-09-14 11:00:00"

Message formats vary by release and some values may be redacted as <private>. Retention is limited, so collect logs early.

Writing it up

  • State capabilities, not actions: "Terminal held Full Disk Access from 10:11:37 UTC", then cite the artifact that shows use.
  • Cite the database and account for every row, and say when a row was recovered from the WAL.
  • Hedge auth_reason interpretations as community-documented.
  • Note your own collection-time grants so they are not mistaken for attacker activity.

FAQ

Is Full Disk Access for Terminal a sign of compromise?

Not by itself. Developers and administrators grant it routinely. It becomes significant when the grant time lines up with other suspicious activity, when the user's role does not need it, or when it is followed by Automation, folder or removable-volume grants for the same app.

Can malware grant itself TCC permissions?

Normally a user prompt, an MDM policy or a system decision is required. Techniques to get there include tricking the user into approving a prompt, borrowing the permissions of an app that already has them, and editing the database directly where protections allow it, for example the system database when SIP is disabled.

Where do I find evidence that a permission was used?

Not in TCC.db, which only stores decisions. Look at the unified log (subsystem com.apple.TCC for requests), process execution evidence, shell history, file system timestamps and EDR telemetry.

How can I tell an MDM-granted permission from a user-granted one?

Check auth_reason (6 is commonly read as MDM policy), policy_id and the policies table, and MDMOverrides.plist. Confirm with the installed configuration profiles. A PPPC profile you cannot explain is a finding.

Related articles

Step by step: load macOS TCC.db files and their WAL into a free in-browser parser, read the findings, review permissions and history, and export.
What the macOS TCC database records, what it proves and what it does not, the services that matter, and a repeatable workflow for reviewing TCC.db in a case.
Where the system and per-user TCC.db files live, why Full Disk Access and SIP matter, and how to collect them with the WAL using UAC, Aftermath or Velociraptor.