iTerm2

iTerm2 Profiles & SSH Configuration

Overview

iTerm2 stores its configuration in the preferences plist ~/Library/Preferences/com.googlecode.iterm2.plist. The forensically richest part is the New Bookmarks array — iTerm2's internal name for the list of user profiles. Each profile is a dictionary describing a saved terminal configuration, and profiles frequently embed the details of remote systems the user connects to: SSH hostnames, ports, usernames, and private-key paths, either as first-class fields or inside a custom launch command such as ssh deploy@prod-web-01.

Profiles map a subject's remote infrastructure. A developer or administrator typically defines a profile per server or environment, so the profile list is effectively an inventory of the machines the user works with — valuable for lateral-movement and scope analysis. Each profile can also carry trigger rules that automatically act on matching terminal output (highlighting text, sending a password, launching a coprocess or script), which reveal automation the user configured and can expose credentials.

Forensic Significance

Evidence TypeForensic Value
Profile inventoryRemote systems and environments the user routinely accessed
SSH host / port / userDirect mapping of remote infrastructure and credentials-in-use
SSH key pathWhich private key authenticates to a given host
Custom commandThe exact command a profile launches (often ssh …)
Initial directoryWorking directory a session starts in
TriggersAutomated actions — password sends, coprocesses, scripts — on terminal output
Badge / tagsUser labelling that groups hosts by environment or role
Dynamic profilesExternally-managed profiles that may indicate MDM or tooling

File Locations

ArtifactPathFormat
Preferences plist (profiles)~/Library/Preferences/com.googlecode.iterm2.plistBinary or XML plist
Dynamic profiles~/Library/Application Support/iTerm2/DynamicProfiles/*.jsonJSON

Profiles live in the New Bookmarks array of the plist. Dynamic profiles are a separate mechanism: JSON files under DynamicProfiles/ that iTerm2 loads at launch, each with a top-level Profiles array using the same key vocabulary. Dynamic profiles are commonly written by scripts, tooling, or device management, so their presence is itself notable.

cfprefsd caching

On a live system, the on-disk com.googlecode.iterm2.plist may lag behind iTerm2's in-memory state because macOS caches preferences in cfprefsd. For maximum fidelity, prefer analysis of a disk image or flush preferences before collection. This is a macOS-wide plist behaviour, not specific to iTerm2.

Profile Fields

Each profile dictionary in the New Bookmarks array may contain the following keys (plist key on the left, meaning on the right). Dynamic profile JSON files use the same key names.

Plist KeyDescription
NameProfile display name
GuidUnique profile identifier
CommandLogin command (used when the profile runs a command instead of a login shell)
Custom CommandCustom launch command string — frequently ssh user@host
HostSSH hostname (iTerm2 SSH integration profiles)
PortSSH port
UsernameSSH / login username
SSH KeyPath to the private key used for the connection
Working DirectoryInitial working directory for the session
Badge TextOn-screen badge overlay (often the hostname or environment)
TagsUser-assigned labels grouping the profile
TriggersArray of trigger rules (see below)

SSH Detection

A profile is treated as an SSH connection when it carries a non-empty Host field, or when its Command/Custom Command invokes the ssh client (a whole ssh token, or a path ending in /ssh). macfor sets an is_ssh flag on the emitted record accordingly, so SSH targets can be filtered out of the full profile list quickly.

Triggers

Triggers fire an action when a regular expression matches terminal output. Each trigger dictionary in a profile's Triggers array contains:

KeyDescription
regexRegular expression matched against terminal output
actionTrigger action class (see table)
parameterAction-specific parameter (text to send, command to run, highlight colour, …)
partialWhether the trigger may fire on a partial (unterminated) line
enabledWhether the trigger is active

Common action values and their forensic meaning:

ActionMeaningForensic Note
PasswordTriggerSend a stored password when promptedIndicates automated credential entry to a keychain-stored secret
SendTextTriggerSend fixed text to the terminalparameter may contain literal credentials or commands
CoprocessTriggerLaunch a coprocessExternal process wired to terminal output
ScriptTrigger / RunCommandTriggerRun a command/scriptAutomation that may execute arbitrary code
HighlightTriggerColour matching textBenign, but reveals what the user watches for
BounceTriggerBounce the Dock iconBenign notification behaviour

Triggers can carry credentials

SendTextTrigger parameters sometimes contain plaintext passwords or tokens that a user configured to auto-send. PasswordTrigger references a secret stored in the login keychain. Review every trigger parameter value — it is a common location for accidentally-exposed credentials.

Parsed Record Schema

macfor emits one iterm2_profile record per profile (from both the plist and any dynamic profile files).

FieldTypeDescription
typestringAlways iterm2_profile
appstringAlways iterm2
userstringLocal user account the profile belongs to
namestringProfile name
guidstringProfile GUID
custom_commandstringCustom launch command, if set
commandstringLogin command, if set
hoststringSSH hostname, if set
portintSSH port, if set
usernamestringSSH / login username, if set
ssh_key_pathstringPrivate-key path, if set
initial_directorystringInitial working directory, if set
badge_textstringBadge overlay text, if set
tags[]stringUser-assigned tags
triggers[]objectTrigger rules (regex, action, parameter, partial, enabled)
is_sshboolWhether the profile represents an SSH connection
is_dynamicboolWhether the profile came from a DynamicProfiles/ JSON file
source_filestringAbsolute path to the plist or dynamic-profile file

Manual Inspection

# Convert the (binary) plist to readable XML/JSON
plutil -convert xml1 -o - ~/Library/Preferences/com.googlecode.iterm2.plist | less

# Extract profile names and any SSH hosts
plutil -convert json -o - ~/Library/Preferences/com.googlecode.iterm2.plist | \
  python3 -c "
import sys, json
prefs = json.load(sys.stdin)
for p in prefs.get('New Bookmarks', []):
    print(p.get('Name'), '|', p.get('Custom Command',''), '|', p.get('Host',''), p.get('Username',''))
"

# List dynamic profiles
ls -la ~/Library/Application\ Support/iTerm2/DynamicProfiles/

Analysis Notes

  • Infrastructure map: The profile list is a curated inventory of the remote systems a subject worked with. Combine host, username, port, and custom_command to enumerate SSH targets.
  • Key-to-host mapping: ssh_key_path links a specific private key to a host, helping attribute authentication and identify which key material to preserve.
  • Custom commands: Profiles often launch SSH via Custom Command rather than the structured Host field — always inspect custom_command, not just host.
  • Dynamic profiles: Externally-managed. If a DynamicProfiles/ file was written by tooling or an MDM, it may reveal an automated deployment or a persistence mechanism; note its modification time and origin.
  • Trigger review: Enumerate every trigger's action and parameter. Password/send-text triggers are a credential-exposure hotspot; coprocess/script triggers are an automation and potential code-execution vector.
  • Cross-reference SSH artifacts: Correlate hosts and usernames with ~/.ssh/config, ~/.ssh/known_hosts, and the iTerm2 remote-host history.

Tool Support

ToolSupport
macforFull extraction of profiles, SSH fields, triggers, and dynamic profiles with an is_ssh flag
plutil / defaults (macOS built-in)Read and convert the preferences plist
python3Parse converted JSON to enumerate profiles and triggers

References