TCC.db: macOS Privacy Permission Grants
The macOS TCC databases record which apps were allowed or denied camera, microphone, screen, disk and automation access, and when that last changed.
- Location
- /Library/Application Support/com.apple.TCC/TCC.db
- Proves
- Which programs requested or were granted sensitive privacy permissions, by whom, and when the decision last changed
- Timestamps
- Unix epoch seconds (UTC) in last_modified
- Access
- Full Disk Access to read; system database also SIP-protected
- Retention
- Until the row is changed, reset (tccutil) or the app is removed
- Collection
- Aftermath, mac_apt, UAC, Velociraptor
Tools
Compare all tools- TCC ParserIn browser
- mac_aptCLI · open source
- PlasoCLI · open source
- VelociraptorPlatform · open source
- sqlite3CLI · built into macOS
What it is
Transparency, Consent and Control (TCC) is the macOS framework that gates access to privacy-sensitive resources: camera, microphone, screen capture, input monitoring, accessibility APIs, protected user folders, Full Disk Access and Apple Events automation. The daemon tccd makes the decisions and stores them in SQLite databases named TCC.db, one for the system and one per user.
Each row is a standing decision for a client (bundle ID or path) and a service. The database is a permissions register, not a usage log: it tells you what a program was allowed to do, not every time it did it.
Where it lives
| Scope | Path | Version notes | Protection |
|---|---|---|---|
| System | /Library/Application Support/com.apple.TCC/TCC.db | access schema changed in 11 Big Sur and 14 Sonoma | SIP + TCC, needs Full Disk Access to read |
| Per user | ~/Library/Application Support/com.apple.TCC/TCC.db | Same schema as system | TCC, needs Full Disk Access to read |
| MDM grants | /Library/Application Support/com.apple.TCC/MDMOverrides.plist | Managed Macs | SIP-protected directory |
| Screen Recording reminder dates | ~/Library/Group Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist | 15 Sequoia+ | TCC-protected |
Collect the WAL and SHM companions (TCC.db-wal, TCC.db-shm) with each database. Every account under /Users has its own per-user copy.
What it proves
- A given app or binary holds, or was refused, Full Disk Access, Accessibility, Screen Recording, Input Monitoring, camera or microphone.
- A path-based client (
client_type = 1) such as an unsigned binary or script interpreter was granted a capability, which is unusual for legitimate software. - An Automation grant lets one app send Apple Events to another (target in
indirect_object_identifier). - The decision came from the user, the system or an MDM policy (
auth_reason, cross-checked withMDMOverrides.plist). - Approximate time of the latest change to a decision (
last_modified).
It does not prove that the permission was actually used, how often, or what was captured. A missing row does not prove a permission was never granted: tccutil reset deletes rows.
Key fields
Table access (Big Sur and later):
| Column | Meaning |
|---|---|
service | Service identifier, e.g. kTCCServiceSystemPolicyAllFiles (Full Disk Access), kTCCServiceAccessibility, kTCCServiceScreenCapture, kTCCServiceListenEvent, kTCCServiceAppleEvents |
client | Bundle ID or absolute path of the requesting program |
client_type | 0 bundle ID, 1 absolute path |
auth_value | 0 denied, 1 unknown, 2 allowed, 3 limited |
auth_reason | Community-documented: 1 error, 2 user consent, 3 user set, 4 system set, 5 service policy, 6 MDM policy, 7 override policy, 8 missing usage string, 9 prompt timeout, 10 preflight unknown, 11 entitled, 12 app type policy |
auth_version | Record format version |
csreq | Code-signing requirement blob identifying the client |
policy_id | Link to an MDM policy, when present |
indirect_object_identifier_type, indirect_object_identifier, indirect_object_code_identity | Target of the grant (Automation) |
flags | Additional flags |
last_modified | Last change to the row |
pid, pid_version, boot_uuid, last_reminded | Added in macOS 14 Sonoma |
On Mojave and Catalina the table used allowed and prompt_count instead of auth_value and auth_reason. Always run .schema access first.
Timestamps
last_modified is Unix epoch seconds, UTC, unlike most Apple databases that use Mac absolute time. It reflects the last write to that row (prompt answered, toggle flipped, policy applied), not the first grant.
SELECT service, client, auth_value, auth_reason,
datetime(last_modified, 'unixepoch') AS last_modified_utc
FROM access ORDER BY last_modified DESC;
last_reminded (Sonoma and later) is also Unix epoch seconds; its schema default is strftime('%s','now'). File system birth and modification times of TCC.db (APFS, nanosecond precision) only tell you when the database changed, not which row.
Retention
Rows persist until the decision is changed, the client is reset with tccutil reset <service> [bundle-id], the user resets permissions in System Settings, or the database is rebuilt. There is no automatic ageing. Deleted rows may survive for a while in the WAL file or free pages, and older copies may exist in local APFS snapshots or Time Machine backups.
Collection
The collector process (Terminal, the agent, or the tool binary) must hold Full Disk Access on a live system, or the copy fails silently or comes back empty.
# Live, with FDA granted to Terminal
sudo ditto "/Library/Application Support/com.apple.TCC" ./case/tcc_system
for u in /Users/*; do
[ -d "$u/Library/Application Support/com.apple.TCC" ] && \
sudo ditto "$u/Library/Application Support/com.apple.TCC" "./case/tcc_$(basename "$u")"
done
- Aftermath copies the system and per-user
TCC.dbandMDMOverrides.plist(run as root with FDA), but notTCC.db-wal: changes still in the WAL, and the older row versions it holds, are lost. - UAC collects both system and per-user
TCC.db(files/system/tcc.yaml), but notTCC.db-walorTCC.db-shm, with the same loss. Copy the companions yourself, as in the commands above. - Velociraptor
MacOS.System.TCCreads both databases directly. - Dead-box: mount the Data volume read-only; TCC and SIP do not restrict reads from an analysis host.
Parsing
- sqlite3 on a copy, with the queries above.
- mac_apt
TCCplugin:python mac_apt.py -o out E01 mac.E01 TCC. - Plaso
macostccSQLite plugin:log2timeline.py --parsers 'sqlite/macostcc' --storage-file tcc.plaso ./case. - Velociraptor
MacOS.System.TCCartifact for fleet hunting.
High-risk review:
SELECT service, client, client_type, auth_value, auth_reason,
datetime(last_modified,'unixepoch') AS changed_utc
FROM access
WHERE auth_value = 2
AND (service IN ('kTCCServiceSystemPolicyAllFiles','kTCCServiceAccessibility',
'kTCCServiceScreenCapture','kTCCServiceListenEvent',
'kTCCServicePostEvent')
OR client_type = 1);
TCC Parser decodes system and per-user TCC.db files with their -wal (including older row versions carved from it), MDMOverrides.plist and csreq blobs in the browser, and flags risky grants; nothing is uploaded.
Investigator tips
- Grants to interpreters or terminals (
/bin/bash,/usr/bin/osascript,com.apple.Terminal) cover everything launched through them. Pivot to shell history and launchd jobs. - A denied row (
auth_value = 0) is still evidence of a request, often the first visible attempt by malware. auth_reason = 6points to MDM. Confirm withMDMOverrides.plistandsudo profiles show -type configuration; a rogue profile is a finding in itself.tccddecisions are logged under subsystemcom.apple.TCCin the unified logs, which is where per-request evidence lives.- On Sequoia, far-future dates in
ScreenCaptureApprovals.plistindicate someone suppressed the periodic Screen Recording reminder. - Endpoint Security exposes TCC changes to EDR tools from macOS 15.4 (
ES_EVENT_TYPE_NOTIFY_TCC_MODIFY); check your EDR telemetry for changes that the database no longer shows. - Compare
csreqwith the signature of the binary on disk: a bundle-ID row is honoured for any code that satisfies the stored requirement. - See the TCC database forensics guide for service lists and query patterns.