Skip to content

File accessUser activity

Spotlight Store (.Spotlight-V100): macOS Metadata Index

Per-volume Spotlight index and per-user CoreSpotlight stores holding file metadata such as download origin, last used date and use count.

Location
/System/Volumes/Data/.Spotlight-V100/Store-V2/<UUID>/store.db
Proves
Where a file came from, when it was added and opened, and that it existed even after deletion
Timestamps
Mac absolute time (seconds since 2001-01-01 UTC); mdls shows UTC
Access
root; Full Disk Access on a live system
Retention
Until the indexer updates or purges the entry, or the index is rebuilt
Collection
mac_apt, Disk image, ditto

What it is

Spotlight keeps a metadata index for every indexed volume. The mds family of processes extracts attributes (kMDItem*) from each file and stores them in a proprietary database under .Spotlight-V100 at the volume root. Since macOS 10.13, each user also has CoreSpotlight stores, where apps donate searchable content.

The value for an investigation is metadata that the file system does not keep: download URL, date added to a folder, last used date and use count. Because the store is updated asynchronously, it can still hold entries for files that were deleted. The Spotlight forensics guide covers live querying and attributes in depth; this page is the quick reference.

Where it lives

Scope / macOSPathNotes
Boot Data volume, 10.15+/System/Volumes/Data/.Spotlight-V100/Store-V2/<UUID>/store.db, .store.db and support files
Boot volume, 10.14 and earlier/.Spotlight-V100/Store-V2/<UUID>/Same structure
External / removable volume/Volumes/<name>/.Spotlight-V100/Shows the drive was indexed by a Mac
User CoreSpotlight, 10.13 to 11~/Library/Metadata/CoreSpotlight/index.spotlightV3/App-donated content
User CoreSpotlight, 12+~/Library/Metadata/CoreSpotlight/NSFileProtectionComplete/index.spotlightV3/ and sibling NSFileProtectionCompleteUnlessOpen, NSFileProtectionCompleteUntilFirstUserAuthentication foldersSome of these can be encrypted
Spotlight bar shortcuts, 10.15~/Library/Application Support/com.apple.spotlight/com.apple.spotlight.ShortcutsTyped search terms and chosen result
Spotlight bar shortcuts, 11 to 13~/Library/Application Support/com.apple.spotlight/com.apple.spotlight.Shortcuts.v3As above
Spotlight bar shortcuts, 14+~/Library/Group Containers/group.com.apple.spotlight/com.apple.spotlight.Shortcuts.v3As above

Protection: .Spotlight-V100 is root-owned and privacy-protected, so a live read needs root and Full Disk Access. User ~/Library stores need Full Disk Access for the collector.

What it proves

  • Download origin (kMDItemWhereFroms), even when the browser history was cleared.
  • When an item arrived in its current folder (kMDItemDateAdded).
  • That a file was opened through Launch Services, when last, and on which days.
  • That a file existed at some point, via entries surviving in the store after deletion.
  • What a user typed into the Spotlight bar and which result they picked (shortcuts file).

It does not prove:

  • Every access. Reads with cat, scripts or direct file APIs do not update usage attributes.
  • Absence. Excluded folders, volumes with .metadata_never_index, disabled indexing and indexing lag all leave gaps.

Key fields

AttributeMeaning
kMDItemWhereFromsDownload URL and referrer; comes from the com.apple.metadata:kMDItemWhereFroms xattr
kMDItemDateAddedWhen the item was placed in its current parent folder
kMDItemLastUsedDateLast open through Launch Services
kMDItemUseCountNumber of recorded uses (not always present)
kMDItemUsedDatesArray of days the item was used
kMDItemFSCreationDate, kMDItemFSContentChangeDateFile system dates as indexed
kMDItemContentType, kMDItemContentTypeTreeUniform Type Identifier; spots renamed executables or disk images
kMDItemFSName, kMDItemDisplayNameFile name as indexed

In spotlight_parser output each record starts with Inode_Num, Flags, Store_ID, Parent_Inode_Num and Last_Updated. The inode and parent inode are how full paths are rebuilt; Last_Updated is when the index record was last written, not a file time.

Timestamps

Attribute dates in the store are Mac absolute time: seconds (stored as a double) since 2001-01-01 00:00:00 UTC. Add 978307200 to get Unix time. The per-record update time is different: spotlight_parser decodes it as microseconds since the Unix epoch. mdls and both parsers print converted UTC values.

# Convert a raw Mac absolute time value on macOS
date -u -r $(( 780000000 + 978307200 ))

kMDItemUsedDates values are day-granular; do not read a time of day into them.

Retention

There is no time-based expiry. An entry lives until the indexer updates or removes it, the volume is reindexed (mdutil -E, or macOS rebuilding a damaged index), or indexing is turned off. Entries for deleted files can linger for some time, and the hidden .store.db can hold items that differ from store.db.

Collection

Collect the whole Store-V2/<UUID> folder, not only store.db: the dbStr-* map files and journals belong to that store instance.

# Live, root, terminal with Full Disk Access
sudo ditto /System/Volumes/Data/.Spotlight-V100 /Volumes/CASE/MBP01/Spotlight-V100
ditto ~/Library/Metadata/CoreSpotlight /Volumes/CASE/MBP01/CoreSpotlight_user
  • mac_apt SPOTLIGHT reads volume and user stores straight from an image; SPOTLIGHTSHORTCUTS handles the shortcuts plists.
  • UAC full profile collects the Spotlight shortcuts files (files/applications/spotlight.yaml); copy .Spotlight-V100 separately.
  • Before collecting, record mdutil -s / (read only). Never run mdutil -E or mdutil -i off on evidence.

Parsing

spotlight_parser (Python 3, needs lz4 and pyliblzfse) takes one database and an output folder:

python3 spotlight_parser.py -p MBP01 /cases/MBP01/Spotlight-V100/Store-V2/<UUID>/store.db /cases/MBP01/spot_out
python3 spotlight_parser.py -p MBP01_hidden /cases/MBP01/Spotlight-V100/Store-V2/<UUID>/.store.db /cases/MBP01/spot_out

It writes a _data.txt dump of every record and a _fullpaths.tsv mapping of inode to path. Its author recommends mac_apt for SQLite output and per-app views:

python3 mac_apt.py -o /cases/MBP01/mac_apt E01 /cases/MBP01.E01 SPOTLIGHT SPOTLIGHTSHORTCUTS

When mac_apt processes .store.db, it only writes items that are new or different from store.db (the .store-DIFF output).

Live alternative, for targeted checks only:

mdls -name kMDItemWhereFroms -name kMDItemDateAdded -name kMDItemLastUsedDate -name kMDItemUseCount ~/Downloads/tool.dmg
mdfind 'kMDItemWhereFroms == "*example.com*"'

Investigator tips

  • Parse both store.db and .store.db; the differences can hold deleted or older entries.
  • Filter parsed output by path (Users/*/Downloads, private/tmp, Users/Shared) and by kMDItemContentType (applications, disk images, scripts, archives).
  • Pivot kMDItemWhereFroms to Safari history and quarantine events to confirm the download.
  • Use FSEvents to bracket when a store-only (deleted) file was removed.
  • A .Spotlight-V100 folder on a USB drive shows it was mounted on a Mac; see USB devices.
  • Mounting an evidence image read-write can trigger indexing and change the store. Mount read-only.
  • Indexing can be switched off per volume. Check mdutil and mds activity in the Unified Logs if the store looks unexpectedly empty.
  • Validate parser output against a test Mac on the same macOS version; the store format evolves.

See also