The macOS 27 Trust Map: SIP, Code Signing, Gatekeeper, TCC, and the AI Trust Plane
Every technique you will learn in this course does one of three things. It respects a trust boundary, it abuses a gap in one, or it creates evidence that one was crossed. There is no fourth option. That is why the operator who can name every boundary on the target, say what each one enforces, and predict what each one records is the one who controls the engagement instead of guessing through it.
This module is your map. You will inspect every major trust boundary on your Golden Gate lab Mac, with real commands and real output, and you will meet the AI-related trust boundaries as they appear on this macOS 27 build. Apple Intelligence and privileged assistant services predate this release; the research question is which actors, entitlements, and routes changed here. Later phases assume you can read this map without hesitation. When a persistence module says a LaunchAgent survives reboot, you will know which launchd domain owns that decision. When an execution module says a payload must be ad hoc signed, you will know that AMFI is the control being satisfied. When an agentic module points at Siri AI's entitlement list, you will already know what an entitlement is worth.
One habit from module 0.1 carries forward: everything you inspect gets captured as evidence. A trust map you cannot show to a reviewer is just an opinion.
Establish the Trust Baseline
Continue in the Phase 00 lab workspace prepared in module 0.1. The read-only trust survey and workspace verifier used below are already in that package.
Concept: The Layered Model
macOS does not have one security boundary. It has a stack of them, and each layer is owned by a different subsystem with its own policy store, its own enforcement point, and its own telemetry. Here is the map this module walks, with the question an operator asks of each layer:
| Layer | What it enforces | The operator question |
|---|---|---|
| SIP | System file immutability, even for root | Which paths are read-only no matter who I am? |
| Code signing | Binary identity and integrity | Who signed this, and has it been touched since? |
| AMFI | Runtime enforcement of signing policy | Will the kernel kill this code on load? |
| Hardened Runtime | Per-process restriction flags | Which dangerous capabilities are denied even to signed code? |
| Gatekeeper | First-launch assessment of downloaded apps | Does this artifact need user approval to open? |
| Notarization | Apple-issued launch ticket | Has Apple scanned and ticketed this binary? |
| Quarantine | Download provenance marker | Is this file treated as coming from the internet? |
| Sandbox | Process containment profile | What files, network, and IPC can this process reach? |
| TCC | User privacy policy | Which data requires a grant, prompt, or managed policy? |
| launchd | Process lifecycle, domains, and privilege | Who can start, stop, and own this service? |
| MDM and profiles | Enterprise policy overlay | Is there organizational policy above the local admin? |
| Unified logging | System-wide telemetry | What did the platform record about all of the above? |
| AI-related services | Entitlement-rich assistant and model services | Which actors and privileges are present or changed on this build? |
Read the table twice. The last row is a live inventory question, not a claim that assistant or model services first appeared in macOS 27. The rest of this module inspects each row on your machine, in roughly this order.
SIP and the Sealed System Volume
Start at the bottom of the stack, because everything else stands on it. System Integrity Protection, SIP, is a kernel-enforced rule that certain system locations are read-only even for root. It is not a permission system you can configure per file. It is a hard fence around the parts of the OS that implement every other control on the map. If an attacker with root could edit those paths, every other boundary would be theater.
System Integrity Protection status: enabled.
Enabled is the assumed state for this entire course. SIP can only be reduced from Recovery Mode, which requires physical or console access and a reboot, and any reduction is trivially visible to a defender who runs the same command. An operator on a real engagement treats a SIP-disabled host as a finding to report and exploit cautiously, not a condition to create.
SIP's policy fence has a physical counterpart. The operating system is not just protected by rules; it is mounted from a cryptographically sealed volume:
/dev/disk3s1s1 on / (apfs, sealed, local, read-only, journaled)
The device number varies by Mac; identify the root mount by /, not by
disk3s1s1. Read the flags. sealed means the volume carries a Merkle tree of its
content and the kernel verifies it. read-only means no write path exists at
all. This is the Signed System Volume, and it is why the classic move of
"drop a binary into /usr/bin" is not just blocked by SIP policy but
physically impossible on modern macOS. Your payloads will live in writable
places: /tmp, user home paths, and locations you will map in Phase 01.
Code Signing: Identity and Integrity
Code signing answers two questions about every executable on the system: who signed it, and has it changed since signing. Nearly every other boundary on the map uses the answer as input. Gatekeeper checks it. AMFI enforces it. TCC identifies apps by it. If you do not know the signing state of your own tooling, you cannot predict how any gate will treat it.
Executable=/bin/zsh Identifier=com.apple.zsh Format=Mach-O universal (x86_64 arm64e arm64e.x1) CodeDirectory v=20400 size=1478 flags=0x0(none) hashes=41+2 location=embedded Platform identifier=26 Signature size=4202 Signed Time=Aug 8, 2026 at 4:00:07 PM Info.plist=not bound TeamIdentifier=not set Sealed Resources=none Internal requirements count=1 size=64
Four details in this output matter, and learning to read them is a permanent skill for this course.
Format=Mach-O universal (x86_64 arm64e arm64e.x1) shows an x86_64 slice
and two arm64e variants. Golden Gate is an Apple Silicon-only OS, yet zsh still
ships an x86_64 slice. This is the last release with general-purpose Rosetta 2 support, and
universal platform binaries are part of that wind-down. arm64e is the
pointer-authenticated ARM64 variant used by platform code.
Platform identifier=26 identifies a platform-signed binary;
TeamIdentifier=not set means this display does not name a developer team.
Those fields alone do not establish the volume seal. Verify the binary's path
and the volume posture separately before making that claim.
CodeDirectory is the integrity mechanism: a hash over every page of the
binary. Change one byte and the code directory no longer matches.
Build a tiny script and ask codesign what it sees before any signing:
/var/folders/mp/bsl2gzwj4n73flkxdn8bphg00000gn/T//msl-0.2-sign.cij7C0: code object is not signed at all
Now sign it ad hoc and read the signature again:
Executable=/private/var/folders/mp/bsl2gzwj4n73flkxdn8bphg00000gn/T/msl-0.2-sign.cij7C0 Identifier=msl-0.2-sign Format=generic CodeDirectory v=20100 size=157 flags=0x2(adhoc) hashes=1+2 location=embedded Signature=adhoc Info.plist=not bound TeamIdentifier=not set Sealed Resources=none Internal requirements count=1 size=60
Two states, two different conversations with every gate on this map. The
unsigned script reports code object is not signed at all on inspection.
The path suffix varies per run. After codesign --force --sign -, that file carries a code
directory and the flags=0x2(adhoc) marker. Ad hoc signing provides
integrity but no identity. It satisfies "must have some signature" checks
while telling every verifier that nobody stands behind the code.
These are the states you will keep straight for the rest of the course:
| State | Identity | Integrity | What it gets you |
|---|---|---|---|
| Unsigned | none | none | No signature identity; launch result depends on policy and context |
| Ad hoc | no identified developer | yes | Has a code directory but no Developer ID identity |
| Developer ID | an Apple-issued team | yes | Recognized as an identified developer |
| Developer ID plus notarization | team plus Apple ticket | yes | Can satisfy the applicable first-launch policy |
| Platform | Apple platform signature | yes | System trust subject to the relevant policy |
AMFI and Hardened Runtime: Enforcement at Load Time
Code signing is the identity card. AMFI, the Apple Mobile File Integrity
agent, is the guard who checks it. AMFI lives in the kernel and consults a
userland daemon, amfid, to validate signatures as code loads. Confirm both
are alive on your box:
108 root /usr/libexec/amfid 222 root /usr/libexec/syspolicyd
Both run as root, which is exactly what you want from the guards. amfid
validates code signatures at load time. syspolicyd evaluates system policy
decisions, including Gatekeeper assessments, which you will meet in the next
section.
The Hardened Runtime is a set of restrictions a developer opts into at build time, and Apple requires it for notarization. It blocks DYLD environment variable injection, unsigned library loading, debugger attachment, and JIT allocation unless specific entitlements lift each restriction. On this build, the Foundation Models CLI is a useful system-binary example:
Executable=/usr/bin/fm Identifier=com.apple.fm Format=Mach-O universal (x86_64 arm64e arm64e.x1) CodeDirectory v=20500 size=2477 flags=0x10000(runtime) hashes=67+7 location=embedded Platform identifier=26 Signature size=4202 Signed Time=Aug 20, 2026 at 10:40:26 PM Info.plist=not bound TeamIdentifier=not set Runtime Version=27.0.0 Sealed Resources=none Internal requirements count=1 size=60
The line that matters is flags=0x10000(runtime). That flag is the Hardened
Runtime. Ordinary DYLD environment injection into this hardened target is
restricted; check the exact entitlements and policy before claiming an
exception. Phase 03 will show
you what hardened targets do and do not allow, using this exact flag as the
decision point.
Defenders look at the kernel's boot arguments for weakened policy, so you should know what yours hold:
kern.bootargs:
The value after kern.bootargs: is empty, which is the clean state: no boot
arguments are set. If a target ever shows boot arguments that weaken AMFI or
disable library validation, that is both an operator opportunity and a
detection artifact of the first order.
Gatekeeper, Quarantine, and Notarization: The First Launch Gate
Gatekeeper assesses software at launch under the host's policy. It is not a runtime guard. Quarantine commonly triggers the first-open assessment, while the code signature and notarization status inform the verdict. Absence of a quarantine attribute in this file probe does not prove that every launch path will skip assessment.
Two probes establish the gate. The first reads the policy, the second asks Gatekeeper to assess a known-good app so you can see its verdict format:
assessments enabled /System/Applications/TextEdit.app: accepted source=Apple System
assessments enabled is the default and the state you should assume on any
target. accepted with source=Apple System is the verdict shape you will
learn to read. When your own delivered artifact is assessed, the source line
is what tells you which trust path it took.
Quarantine is an extended attribute commonly applied by a download agent. Its fields can identify the agent and event, but the value alone does not prove a particular launch verdict.
com.apple.quarantine: 0083;68ab6c98;Safari;E7C1A1D6-9C4E-4B5D-9C6C-1F2D3E4A5B6C
The format is four fields: a flag word, a timestamp in hex, the agent that downloaded the file, and a UUID for the event. Two operator facts about quarantine will matter to you constantly:
- Propagation depends on the source attribute, copy or extraction tool, and
destination. Module 0.4 measures specific paths. Do not assume that
cp,tar,ditto, orunzipalways preserve or always remove the attribute. Inspect the delivered artifact before making a first-launch prediction. - Removing quarantine with
xattr -dchanges file metadata. That change can be observed by a collector with suitable file telemetry; it does not establish that every host logs the deletion or that no later assessment occurs.
Notarization is the last piece. A developer uploads software to Apple, Apple runs automated scanning, and a ticket is issued. A developer can staple the ticket to the app, or Gatekeeper can obtain it online when connectivity and policy allow. Stapling supports offline verification; it is not mandatory for notarization. This is automated triage, not a security audit. For an operator it is a delivery constraint: notarized Developer ID apps pass Gatekeeper with the least friction, and the Developer ID certificate ties the binary to an identity, which becomes part of your attribution story. Note that platform apps like TextEdit do not carry third-party stapled tickets, so do not use them to learn what a stapled ticket looks like. Phase 01 shows you the real thing on a delivered artifact.
Sandbox: Containment by Profile
The sandbox confines a process to an allowlist: the files, network endpoints, Mach services, and resources its profile permits. App Store apps are sandboxed by default. Command line tools and daemons generally are not. The difference is visible in the entitlements, which are the declared privileges embedded in the signature.
Compare Apple's Calculator with your shell. First, extract the one entitlement that declares sandboxing:
<key>com.apple.security.app-sandbox</key><true/>
The com.apple.security.app-sandbox entitlement set to true is the
declaration. Calculator runs inside a container and reaches only what its
profile allows. Now check the same entitlement on zsh:
App Sandbox entitlement: absent
The displayed shell signature lacks the
com.apple.security.app-sandbox entitlement; Calculator's signature includes
it. That difference is an access-planning lead, not proof that one process can
read every home path while the other can read none. The sandbox profile,
grants, path, and actual caller still matter. Test the specific resource
before claiming reachability. A defender may also collect sandbox denials,
but this entitlement comparison did not capture one.
TCC: Consent as a Boundary
TCC, Transparency Consent and Control, is the privacy gate. When a process wants protected data, contacts, calendar, camera, microphone, location, full disk access, accessibility, screen recording, TCC checks applicable grants and policy. A prompt is one possible result, not the only one. Decisions may be stored in SQLite databases, and their location is worth inspecting:
total 184 drwxr-xr-x 4 root wheel 128 Oct 1 16:50 . drwxr-xr-x 11 root admin 352 Sep 24 02:38 .. -rw-r--r-- 1 root wheel 20480 Oct 1 16:05 REG.db -rw-r--r-- 1 root wheel 73728 Oct 1 16:50 TCC.db user TCC directory: absent for this account
Four lessons in that capture. First, the system database exists at
/Library/Application Support/com.apple.TCC/TCC.db, owned by root. Second,
this Golden Gate build keeps a companion store, REG.db, beside it. Record
its presence and timestamps. The trust plane keeps more than one ledger, and
your job is to notice what is there rather than assume. Third, the user-level
directory does not exist for this account in this capture. That is a scoped
filesystem observation, not a complete history of privacy decisions. Fourth,
you can list these files but you
cannot read the databases themselves without Full Disk Access, which is the
point: the privacy store is itself private.
Two operator questions about TCC shape later phases. Which service is being requested, and which client and responsible process does policy attribute? Code signing can affect that identity, but this signing probe does not predict the next TCC decision. A prompt is one possible path, not a guarantee on every access. Phase 06 measures a specific service and caller before stating the boundary.
launchd: Domains Are Privilege
launchd is PID 1 and manages system and user service domains. It is not the direct parent of every process. It is also a privilege boundary, because the domain a service lives in decides who it runs as and when it starts. There are three locations you must keep straight:
| Location | Domain | Runs as | Starts |
|---|---|---|---|
/System/Library/LaunchDaemons | system | usually root; inspect UserName | boot or configured trigger |
/Library/LaunchDaemons | system | usually root; inspect UserName | boot or configured trigger |
~/Library/LaunchAgents | user domain | account owning the loaded job | login or configured trigger |
Look at your user domain, live:
gui/501 = {
type = login
handle = 100002
active count = 451
service count = 450
active service count = 197
creator = loginwindow[165]
creator euid = 0
session = Aqua
endpoint destination = com.apple.xpc.launchd.domain.user.501
auxiliary bootstrapper = com.apple.xpc.otherbsd (complete)
security context = {
uid = 501This capture is a logged-in Aqua session for uid 501. On your Mac, the UID
will come from id -u; the GUI domain may be absent in an SSH-only or
headless session. A LaunchAgent's actual domain and session type must be
verified from its loaded job, not inferred from the plist location alone.
Phase 07 builds on that distinction.
Now the Golden Gate detail that matters for both offense and detection. Count the daemon plists in the sealed system location versus the third-party location:
425
0This dedicated course VM had 425 plists in the sealed system location and
none in /Library/LaunchDaemons when captured. The count is inventory, not a
universal baseline. A future non-Apple entry in a writable launchd location
is a triage lead; decide what it means from its owner, program path, signing
identity, loaded domain, and change history.
MDM and Configuration Profiles: The Enterprise Overlay
Mobile Device Management is policy imposed by an organization above the local admin: Gatekeeper settings, certificates, enforced login items, FileVault and firewall policy, remote queries. On a managed Mac, your assumptions change, which is why enrollment status is one of the first discovery commands you run on any target. Run it on yours:
Enrolled via DEP: No MDM enrollment: No
Your lab box is unenrolled, which is the clean research state. On a managed fleet the same command reports the enrollment and the MDM server, and every artifact you leave becomes potentially visible to the management channel. Phase 04 turns MDM discovery into a full enterprise footprint assessment. For this module, the rule is simple: query it early, and let the answer shape the rest of the operation.
Unified Logging: A Partial Boundary Record
Several subsystems in this trust map publish unified-log messages, including some policy evaluations, TCC decisions, sandbox denials, and launchd events. The store is not a complete record of every boundary interaction. Level, privacy, retention, and predicate choice limit what a local query returns; other collectors may see different evidence.
Query it for trust-related activity from the last few minutes:
Output depends on activity in the five-minute window. On the validation VM,
this query returned a header and an unrelated syspolicyd certificate-array
error, not evidence of the assessment above. A result from this predicate,
time window, log level, privacy setting, and retention state neither proves
nor disproves that a particular policy decision occurred. Phase 04 teaches
how to correlate an action with a scoped observation.
AI-Related Trust Boundaries on This Build
Apple's assistant and model services existed before macOS 27. On this build, the assistant is an application and a fleet of daemons that mediate actions, hold personal context, and carry private entitlements that no third-party code can obtain. For an operator, that makes the AI surface two things at once: a reconnaissance target, because its privileges define what the platform now trusts, and a discipline, because you must understand it before you can reason about any technique that touches it.
Start with the entitlements of the assistant itself. These are the declared
privileges embedded in the signature of /System/Applications/Siri AI.app:
[String] com.apple.assistant.request-dispatcher.uibridge-service [String] com.apple.assistant.uibridge-service [String] com.apple.campo [Key] com.apple.Contacts.database-allow [Key] com.apple.FaceTime.NoPrompt [Key] com.apple.Pasteboard.background-access [Key] com.apple.QuartzCore.global-capture [Key] com.apple.accounts.appleaccount.fullaccess [Key] com.apple.apfs.unlock [Key] com.apple.assistant.request-dispatcher.uibridge-service [Key] com.apple.assistant.uibridge-service [Key] com.apple.menubar.campo [Key] com.apple.runningboard.assertions.angeltarget.campo
Thirteen lines, reproduced from this build's signature. Read them as declared
capabilities, not proof that each operation succeeded in this session. The
application identifier is com.apple.campo; several other keys refer to
Contacts, FaceTime, pasteboard, capture, account, APFS, and UI bridge surfaces.
None of those strings is a vulnerability by itself. The operator skill is to
separate entitlement possession from actual operation and caller reachability.
Save the list as a build-specific inventory, then test any proposed route
under the relevant session and policy.
The assistant is not one process. It is a fleet. List the ones running in your session:
699 0 com.apple.intelligenceplatformd 486 0 com.apple.campo 845 0 com.apple.intelligencetasksd 676 0 com.apple.siri.context.service 578 0 com.apple.CampoRemoteService - 0 com.apple.SiriTTSTrainingAgent - 0 com.apple.callintelligenced 653 0 com.apple.intelligenceflowd 697 0 com.apple.siriactionsd 598 0 com.apple.siriknowledged 1356 0 com.apple.siriappintentsd 690 0 com.apple.siriinferenced 666 0 com.apple.intelligencecontextd 510 0 com.apple.visualintelligenced
This logged-in validation session listed fourteen matching services; a dash means launchd has a registered job with no current PID. Membership and PIDs vary with the session and activity. Treat this as a session-local observation, not a complete roster. A broader inventory requires inspecting launchd plists and process state in the relevant user session. Compare each service's privileges and reachability before treating it as an operator path; a name alone proves neither when it first appeared nor who can reach it.
Model availability depends on the caller's context. Ask the Foundation Models CLI what it can establish in this session:
System model unavailable: deviceNotEligible
The disposable macOS 27 VM returned deviceNotEligible after the CLI's legal
notice was accepted. A physical host may differ. fm available is a
caller/device eligibility check, not proof of
a completed inference or of where a later request will be processed. It also
does not establish Private Cloud Compute policy.
This build ships an Endpoint Security tracer at /usr/bin/estrace,
a symlink to eslogger. It is a first-party tool you can use to measure
specific events when the required privileges are available. Confirm that
the tool exists before planning such a measurement:
-rwxr-xr-x 1 root wheel 1372112 Sep 24 02:10 /usr/bin/eslogger lrwxr-xr-x 1 root wheel 8 Sep 24 02:10 /usr/bin/estrace -> eslogger
A dedicated lab later in the course, module 2.9, turns estrace into your
visibility tester. For this module, it belongs on the map as an available
measurement tool, not as proof of what any endpoint product collects.
One Launch, Every Boundary
The layers do not act alone, and the fastest way to internalize the map is to consider a single ordinary action through the stack. Suppose a user downloads a signed, notarized app, extracts it, and opens it. The checks below are questions to verify on that host, not a guaranteed event sequence:
- Did the download agent attach quarantine, and did extraction preserve it?
- Which app identity did LaunchServices receive at first open?
- Did policy assess the artifact, and which signature/notarization state was used? Was a ticket stapled or fetched online?
- What did code-signing and Hardened Runtime policy enforce at launch?
- If the app requested camera access, did TCC use an existing grant, managed policy, a prompt, or a denial?
- If sandboxed, which file or IPC action did the app attempt and was it allowed?
- Query the relevant logs and sensors for evidence of each step; not every transition is guaranteed to produce a retained, visible unified-log entry.
Content that an assistant app reads, summarizes, or acts on crosses a separate application trust boundary. Its configured tools, entitlements, user consent, and policy determine which actions are possible; model output alone grants no authority. Phase 01 tests that distinction in a lab app. For now, hold the lesson: any single operator action can touch five or more boundaries at once, and each contact is a place the action can fail and a place it leaves evidence.
Automate the Survey
You ran every probe by hand so you would learn what each one means. Now take the fast path. The phase pack ships a read-only survey script that runs the whole map and stores each result in your evidence directory:
captured sip-status.txt (exit=0) captured gatekeeper-status.txt (exit=0) captured gatekeeper-assess.txt (exit=0) captured codesign-zsh.txt (exit=0) captured codesign-fm.txt (exit=0) captured mdm-enrollment.txt (exit=0) captured tcc-system.txt (exit=0) captured tcc-user.txt (exit=1) captured launchd-user.txt (exit=0) captured nvram-boot-args.txt (exit=0) captured amfid-process.txt (exit=0) captured sealed-volume.txt (exit=0) captured launchd-plist-counts.txt survey complete: /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey (nonzero probes: 1; inspect each exit_status) amfid-process.txt codesign-fm.txt codesign-zsh.txt gatekeeper-assess.txt gatekeeper-status.txt launchd-plist-counts.txt launchd-user.txt mdm-enrollment.txt nvram-boot-args.txt sealed-volume.txt sip-status.txt tcc-system.txt tcc-user.txt
The survey stores each result under $EVIDENCE/trust-survey/ and does not
change system policy. tcc-user.txt returned nonzero because that directory
was absent in this VM session; the script records that status instead of
presenting the probe as successful. Earlier signing and quarantine examples created and
removed temporary files, and the evidence workspace was written. Close by
confirming the workspace holds what you collected:
== MacSec Labs workspace check: 0.2-trust-boundaries == PASS evidence directory exists: /Users/tester01/macseclabs/evidence/0.2-trust-boundaries INFO non-empty evidence files: 17 evidence contents: /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/fm-availability.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/sealed-volume.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/sip-status.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/siri-ai-entitlements.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/amfid-process.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/codesign-fm.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/codesign-zsh.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/gatekeeper-assess.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/gatekeeper-status.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/launchd-plist-counts.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/launchd-user.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/mdm-enrollment.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/nvram-boot-args.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/sealed-volume.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/sip-status.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/tcc-system.txt /Users/tester01/macseclabs/evidence/0.2-trust-boundaries/trust-survey/tcc-user.txt result: workspace check passed
Seventeen files: the four captures you teed along the way, and the thirteen
the survey wrote under trust-survey/. The verifier is read-only and you can
run it any time. Run it early to confirm the workspace exists, and again at
the end of a module to see the evidence you accumulated. That habit, proving
what you collected, is what carries into every engagement report.
This module issued a burst of read-only probes, including csrutil, spctl,
codesign, launchctl, and log show, from the lab user's session. A sensor
with suitable process and argument collection could record and correlate some
of them. This lab did not run such a sensor or demonstrate a product alert,
so it cannot claim that every command line was captured or flagged.
That is the point of doing it openly first. Reconnaissance of the trust
surface is a MITRE ATT&CK discovery pattern, and you now know what yours looks
like from the other side. The filesystem kept its own record too: your
evidence directory now carries a trust-survey folder whose creation time,
owner, and contents all testify to exactly this session.
In later phases you will learn to reduce this signature when the engagement requires it, and you will measure the reduction honestly. The reference point is the loud, complete, verifiable survey you just ran.
Checkpoint
Before module 0.3, confirm you can answer each of these without looking back:
- What does
csrutil statussay on your box, and why can you not change it from a normal session? - What does the
sealedflag on the root mount mean for where your payloads can live? - Name the five code signing states and say what each one gives you.
- Which flag in a
codesign -dvoutput marks the Hardened Runtime, and what did Apple's ownfmCLI show for it? - Why does an unsigned dylib fail against a hardened target? Which two boundaries team up to stop it?
- What did the TCC directory check establish for this account, and what host history cannot be inferred from that absence?
- How many third-party daemon plists sit in
/Library/LaunchDaemonson your box, and why does that number matter for persistence OPSEC? - Which entitlement on Siri AI surprised you most, and why?
If any answer is shaky, re-run that section's commands. The map is only useful if you can draw it from memory.
Module 0.3 takes this map and applies it to the living system: process identity, user context, and session authority, the layer that decides what your code runs as and what it can touch.
This is one free module of many.
Get every module across all ten phases, with working code and the detection engineering to catch each technique.
Get full access