TCC Overview and Internals


TCC (Transparency, Consent, and Control) is a privacy and security feature introduced by Apple in macOS to manage and regulate app permissions and access to user data. The primary purpose of TCC is to provide users with transparency and control over what data applications can access, thereby enhancing user privacy and security.

TCC was first introduced in macOS Mountain Lion (version 10.8) in 2012. Initially, it provided basic privacy controls, such as managing access to location services.

The release of macOS Mojave (version 10.14) in 2018 marked a significant expansion of TCC. Mojave introduced stricter privacy controls and required explicit user consent for apps to access various categories of data, including:

The following releases of macOS through 2019-2021 included permissions for screen recording, access to files in the Desktop and Documents folders, and automation permissions.

Functionality and Features

TCC provides a framework for managing app permissions in macOS. One of it’s main features is the User Consent Dialogs. When an app requests access to a protected resource (e.g., microphone, camera, or location), macOS presents a user consent dialog. The user can either grant or deny access.


As an alternative users can manage permissions through the “Security & Privacy” pane in System Preferences. This interface allows users to review and adjust permissions for various apps and services.




When an application attempts to access a location or service, the TCC daemon, known as tccd, displays a prompt through the notification center.

This TCC prompt appears only the first time the application requests access. Permissions can later be modified in the “Security & Privacy pane of System Preferences”.

TCC operations are primarily managed by the tccd daemon located at /System/Library/PrivateFrameworks/TCC.framework/Resources/tccd. Typically, there are at least two instances of  tccd running: one is a system-wide daemon that runs as root, and the other is a user-mode daemon running with the user’s privileges. The system-wide daemon is configured in /System/Library/LaunchDaemons/

 $ ps aux | grep -v grep | grep tcc                                                 ok
esquilichi        4436   0,0  0,1 408279216   9200   ??  S     4:21PM   0:02.49 /System/Library/PrivateFrameworks/TCC.framework/Support/tccd
root               364   0,0  0,1 408281824   9632   ??  Ss    8may24   1:52.90 /System/Library/PrivateFrameworks/TCC.framework/Support/tccd system

We can see that the one running as the root user has the system argument, to verify it we can read the “plist” that manages this service:

$ cat /System/Library/LaunchDaemons/                                                                                          ok
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">
		<string>system</string> // 1

As we cant see at [1], the argument is defined under the key ProgramArguments to be the system string.

tcc.db Database

TCC.db is a critical component of the Transparency, Consent, and Control (TCC) framework in macOS. It is a SQLite database that stores the privacy preferences and permissions granted by the user for various applications. This database ensures that user consent is consistently enforced across the system, managing access to sensitive data and system resources.

For individual users, the TCC.db file is located at ~/Library/Application Support/

There is also a system-wide TCC.db located at /Library/Application Support/, which manages permissions that apply to all users on the system.

The TCC.db file is a SQLite database containing several tables that record permissions. The primary table of interest is typically named access.

The access table includes columns such as service, client, client_type, allowed, prompt_count, and indirect_object_identifier. These columns track which services (e.g., camera, microphone) each application (client) has requested access to, the type of client, whether access is allowed, how many times the user has been prompted, and other relevant data.

CREATE TABLE access (    
	service        TEXT        NOT NULL,
	client         TEXT        NOT NULL,
	client_type    INTEGER     NOT NULL,
	auth_value     INTEGER     NOT NULL,
	auth_reason    INTEGER     NOT NULL,
	auth_version   INTEGER     NOT NULL,
	csreq          BLOB,
	policy_id      INTEGER,
	indirect_object_identifier_type    INTEGER,
	indirect_object_identifier         TEXT NOT NULL DEFAULT 'UNUSED', 
	indirect_object_code_identity      BLOB,
	flags          INTEGER,
	last_modified  INTEGER     NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER)),
	pid_version INTEGER,
	last_reminded INTEGER NOT NULL DEFAULT 0,
	PRIMARY KEY (service, client, client_type, indirect_object_identifier),

You can check the following information by opening the db file and checking the schema, but you will need FDA (Full Disk Acess) rights.

If we check the data inside the service table, we will see the following services:

sqlite> select DISTINCT service from access;

These services include access to contacts, calendar events, the camera, microphone, photos, reminders, and Bluetooth, as well as permissions for Apple Events, file provider domains, and various system policies related to app bundles, app data, and different system folders (such as desktop, documents, downloads, network volumes, and removable volumes). Additionally, it manages access to iCloud (referred to as Ubiquity) and web browser public key credentials, reflecting macOS’s comprehensive approach to controlling and securing application permissions across multiple domains and ensuring user privacy and data integrity.

The name of these services are normally undocumented and their names change over time.

TCC and Entitlements

For an app to use certain system resources such access to the device camera, it must need the corresponding entitlement, even before prompting for TCC access:

$ codesign -dv --entitlements - /Applications/Visual\ Studio\             
Executable=/Applications/Visual Studio
Format=app bundle with Mach-O universal (x86_64 arm64)
CodeDirectory v=20500 size=768 flags=0x10000(runtime) hashes=13+7 location=embedded
Signature size=9012
Timestamp=7 May 2024 at 07:37:54
Info.plist entries=35
Runtime Version=14.0.0
Sealed Resources version=2 rules=13 files=965
Internal requirements count=1 size=180
		[Bool] true
		[Bool] true
		[Bool] true
		[Bool] true

Visual Studio Code has the following interesting entitlements:


So, if VSCode requests access to these two system resources for the first time, a TCC prompt will be opened. Why is this so interesing from an atacker perspective?

Attacking TCC

The TCC protection changes the theat model landscape of macOS. Normally if we think about privilege escalation we think about the following schema:

intial access -> user access -> root/admin access

But now it can be kind of different, root access is not the most desired one in macOS because if you don´t have access to the resource you need TCC will block you even if being root.

But what happens if we can trick VSCode into executing our malicious code? We can privesc into getting access to more resources.

intial access -> user access -> user access with TCC granted permissions

This seems ok, but how are we going to attack VSCode? We will see it in the next blog post, but remember that this app is built on Electron, and that has unforseen consequences.



We will see how to attack Electron macOS apps in the next blog post.