How to Analyze TCC.db in Your Browser
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.
TL;DR. Collect the com.apple.TCC folders (system and every user, with the WAL), drop them on TCC Parser, and work through the tabs: Findings, Permissions, Apps, Timeline, History, Sources. Set a time range to focus every view on the window you care about, then export CSV, Timesketch CSV or JSON. Parsing runs in WebAssembly in a Web Worker inside your browser: the files are never uploaded.
This is the hands-on companion to the TCC.db forensics guide. The examples use the built-in sample, which is synthetic and fictional: a finance laptop, FIN-MBP-03, user dana.whitlock, where an attacker using a stolen session worked between about 10:05 and 10:50 UTC on 2026-09-14. It belongs to the same fictional intrusion as the Windows host FIN-WKS-07 used on our sister tools.
Apple and macOS are trademarks of Apple Inc. TCC Parser is independent and not affiliated with Apple.
Before you start
| You need | Why |
|---|---|
The system com.apple.TCC folder | Full Disk Access, Accessibility, Screen Recording and MDM grants |
Each user's com.apple.TCC folder | Automation, folders, camera, microphone |
The -wal files | Recent changes and earlier versions of rows |
| The user folder in the path | Attributes each database to an account |
| A current desktop browser | The parser runs as WebAssembly |
Step 1: Collect the com.apple.TCC folders
On a live Mac, grant Full Disk Access to Terminal (or your agent) first, then copy the folders:
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
The same commands, plus UAC, Aftermath, Velociraptor and dead-box options, are in the How to get your data guide under the drop zone and in TCC.db location and acquisition. If your collector copied only TCC.db without TCC.db-wal, the parser still works, but the History tab will have less to show.
Step 2: Load the files
Open the home page. On the drop zone you can:
- drop files, a folder, or a collection archive: a ZIP (Velociraptor, Aftermath
tcc_root/tcc_<user>copies, or a zipped folder) or a UAC.tar.gz, which you do not need to extract first; - click Choose files or Choose a folder;
- click Try a sample to load FIN-MBP-03.
The parser recognizes TCC.db files and pairs each with its -wal, reads MDMOverrides.plist, and loads REG.db and any other SQLite file in the folder as raw tables. The workspace opens full screen; press Esc to leave full screen.
Step 3: Read the Findings tab
Findings are prompts to look, not verdicts. In the sample you will see, among others:
| Finding | Sample row |
|---|---|
| High-impact grant to a terminal | Full Disk Access to com.apple.Terminal, 10:11:37 UTC |
| Path-based client in a hidden folder, ad-hoc code requirement | /Users/dana.whitlock/Library/Caches/.sync/sync-helper |
| Grant removed (only visible in the WAL) | Accessibility for that helper, granted 10:19:05, removed later |
| Denied request from an unusual client | Screen Recording for the helper, denied at 10:24:40 |
| Automation of System Events and Finder | Terminal, 10:14:02 and 10:16:48 |
| Burst of permission changes | Changes from 10:11:37 to 10:24:40, then a 14-minute gap before 10:38:55 |
| MDM-granted row to review | Full Disk Access for com.example.edr.agent from a PPPC profile |
The MDM row is expected on a managed Mac; it is listed so you confirm it, not because it is suspicious. Other finding types include clients in /tmp, /private/var/tmp, /Users/Shared or Downloads, and timestamps in the future.
Step 4: Review the Permissions and Apps tabs
Permissions lists every row from every database, decoded, in these columns:
| Column | Content |
|---|---|
| Last modified | last_modified in UTC |
| Decision | Allowed, denied, unknown or limited |
| Permission | Human name and raw identifier, for example Full Disk Access and kTCCServiceSystemPolicyAllFiles |
| App/program | The client, plus the Automation target when there is one |
| Reason | auth_reason, decoded |
| Database | System or the user's database, so a per-user row stays attributed to its account |
| Review flags | The findings that apply to the row |
Click a row to open its detail panel: client_type, the raw auth_value, the csreq decoded to requirement text, auth_version, flags, the policy, the storage (a TCC.db page or a WAL copy), and buttons to set the time range around this decision.
Apps pivots by client. Open com.apple.Terminal in the sample and you see its whole footprint in one place: Full Disk Access in the system database; Automation of System Events and Finder, Documents and Desktop access, and removable-volume access (10:38:55, the USB volume "EXFIL" in the story) in dana.whitlock's database. That picture is the one you want in the report: one app, many capabilities, all within 30 minutes.
Step 5: Scope a time range on the Timeline
The Timeline tab orders every timestamp. To focus it, and everything else, use the time range bar that sits above all the tabs:
- From and To, to the second;
- a time-field select: Last modified, Last reminded, Expired at or Any of these times;
- presets computed from the data;
- an Around… select;
- a density strip that shows where changes cluster, which you can drag to select a window.
From a row's detail panel you can also set the range around that decision. The range scopes every view, count, finding and export, and it is kept in the URL, so you can bookmark or share the exact view with a colleague who loads the same files. In the sample, a range of 10:05:00 to 10:50:00 UTC isolates the intrusion from the older, legitimate grants (Zoom, Teams camera and microphone, and so on); with the sample loaded, the Use the sample's incident window button on the Findings tab sets it for you.
Step 6: Check History and Sources
History shows rows recovered from WAL frames (older commits, uncommitted frames and frames from an older WAL generation) and from freed pages, compared with the current state. In the sample, it shows the Accessibility grant for the sync-helper that no longer exists in the current database. How and why that works is in recovering removed TCC grants from the WAL.
Sources lists what was loaded: each database, whether a WAL was found and replayed, MDMOverrides.plist, and the raw tables of other SQLite files. Check it before you trust an absence: if a user's database is missing, the answer is a collection gap, not a clean account.
Step 7: Export the evidence
| Export menu entry | Use |
|---|---|
| Permissions (CSV, incl. history) | The decoded rows, including recovered history rows, with a state column (current, expired, removed or earlier) |
| Timeline (CSV) | The timeline, for your case timeline |
| Timeline for Timesketch (CSV) | Import into Timesketch next to other sources |
| Everything (JSON) | Everything, including decoded requirements and recovered history |
When a time range is set, it is part of the file names, so an export always says which window it covers. Record the hashes of the source files you loaded alongside the exports.
What to do next
The sample does not end in TCC.db: in the same story there is 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. Pivoting from TCC rows to those artifacts is covered in investigating TCC permission abuse.