Skip to content

Code identity

How Outbound names a program by its signature and path, and what changes when an app is updated or replaced.

Outbound 1.2.0 · Updated

Before Outbound can ask you about a connection or match a rule to it, it needs to know which program made the connection. It reads that from the running process, not from a name the process reports.

For a connection, the network extension resolves the process and records:

  • The executable path, for example /Applications/Slack.app/Contents/MacOS/Slack. A helper nested inside a framework inside an app is attributed to the outermost .app, so “Google Chrome Helper” counts as Google Chrome.
  • The team identifier on a Developer ID or App Store certificate.
  • The signing identifier, the code’s own name, such as com.apple.Safari.
  • The code directory hash (cdhash), a fingerprint of the exact build.
  • How the code is signed: by Apple, by the Mac App Store, by a Developer ID certificate with a team, ad hoc, or not at all.

The result is cached for that process instance (the same process id and start), so a long-running app is inspected once.

A signing identifier on its own proves nothing: anyone can ad-hoc-sign a binary that claims to be com.apple.Safari. Outbound accepts a signing identifier when a team identifier on a Developer ID or App Store certificate backs it, or when the code carries Apple’s own signature and that signature checks out.

An ad-hoc signature can claim any team identifier, so Outbound drops the team and identifies that program by its path. A rule for an ad-hoc binary covers that path, not every binary that claims the same identifier. A self-signed certificate is treated the same way: nobody vouches for it.

A program with neither a signing identifier nor a path is never asked about and never allowed while Outbound is not running: those connections are blocked. When you answer an alert for a program that cannot be named, the answer applies to that connection only.

Rules can match Apple-signed code by that signature rather than by path or hash. The signature travels with the bytes, so a copy made with cp is still Apple-signed. Only System Integrity Protection locations count:

  • Apple apps: inside an .app bundle under /System/Applications/, /System/Library/, /System/Cryptexes/, /System/Volumes/Preboot/Cryptexes/ or /Library/Apple/.
  • System services: outside any .app, under /System/, /usr/libexec/, /usr/sbin/ or /Library/Apple/. The built-in group names daemons such as mDNSResponder, trustd and apsd.

Command-line tools in /usr/bin and /bin (curl, ssh, python3) are Apple-signed and are in neither group. Apple apps installed into /Applications, such as Xcode or Pages, are asked about like any other app.

The app is updated in place. A normal update of an app in /Applications keeps the same code identity, so a code-identity rule still matches. For the layouts Outbound knows (Homebrew Cellars under /opt/homebrew/Cellar/ and /usr/local/Cellar/, and CoreSimulator runtimes), a rule you save from a versioned path is written as a pattern, so a Homebrew formula keeps matching after the version number in the path changes.

The binary at a path is replaced. A path rule that allows or asks can be pinned to the approved hash: it matches only code with that hash. Replace the binary and that rule stops matching. If some other rule would still allow or ask, and a pinned path’s hash has changed, Outbound sets that rule aside: Strict blocks the connection, and Learn and Ask ask about it, so you approve the new code yourself. If nobody answers, the connection is blocked. A block in Strict lands in Review as “Changed binary”. A block is never narrowed this way. Whatever runs at a blocked path stays blocked. In Learn and Ask, a replaced pinned binary is asked about even when no other rule matches.

The developer re-signs with a different team. A code-identity rule names a specific team and signing identifier, so code signed by a different team no longer matches it. When no other rule matches, Outbound treats that code as an unknown program: Learn allows it and files it in Review, Ask asks, and Strict blocks it.

Where Outbound can, it shows who made an app: the name on the Developer ID certificate, such as “Slack Technologies, Inc.”, and only when that certificate validates for the same team the filter verified. An app Apple re-signed for the Mac App Store is shown as “the Mac App Store”. A self-made certificate that merely claims a company name is never shown.