Lab Technical Report LAB-TR-0013

Residual Traces of Removed Messages in the iOS Unified Log: An Observational Study

Lab Technical Report, preprint, not peer reviewed

Abstract

Deleted messages may leave traces in the iOS unified log, but no measurement shows how often the log names a message. We read the unified logs and Messages stores of 27 iOS full file system extractions in the Lab's research corpus (iOS and iPadOS 14 to 26) with our own reader and compared the UUIDs in 533.8 million log records with the stores' identifiers. The log named 24% of the 2,867 messages dated inside a device's Persist span: 60% of those under a day old, 0.1% of those 7 to 14 days old, and received messages (32%) more often than sent ones (11%). Notification, Focus and sharing components named them; the messaging subsystems withheld 54% of their strings and named none. Messages in Recently Deleted were named no more often than other messages (68 of 407 against 85 to 109 expected), but the delete date almost always equals the message date, so deletion time could not be tested. After three tests, 189 message-like identifiers that the store lacks remain, on 10 devices, mixed with other identifiers. No marker experiment was run. The log can corroborate that a recent message existed; it did not show that one was removed.

CCS Concepts • Applied computing → System forensics; • Security and privacy → Mobile platform security.

Keywords mobile forensics, iOS, unified log, Messages database, deleted messages, message identifiers, redaction, retention, observational study

ACM Reference FormatDaniel Addai, Selorm Adjabeng, Kingsley Albert Egyir, and Sanders Larweh Tetteh. 2026. Residual Traces of Removed Messages in the iOS Unified Log: An Observational Study. Lab Technical Report LAB-TR-0013, version 1.0. SectraTEK Lab, Prudential Associates. Preprint, not peer reviewed. https://lab.sectratek.com/research/reports/lab-tr-0013/

1 Introduction

Examiners may expect the iOS unified log to keep traces of messages that a user later deleted. The Messages store removes the row, but other components write to the log while they handle a message, to raise a notification, to evaluate a Focus or to index a shared photo, and some of them print the message's identifier. If the log names a message that the store no longer holds, it would show that the message existed. Practitioners describe the log as short-lived and variable [6], but in what we found nobody has measured which identifiers the log holds for messages, for how long, or what redaction leaves linkable.

A motivating example. Figure 1 shows a log record as this study reads it (synthetic values). A public item holds a UUID. If the Messages store has a message with that GUID, the record names an existing message. If it has none, the value may be a message that was removed, but it may equally be a message the phone handled and never stored, an identifier of another kind, or a value from another account. Which reading holds depends on how often each case occurs, and that has not been counted. On the devices studied here, 24% of the messages dated inside a device's log span are named in it, 83% of those named within a minute of their date, and the log also holds UUIDs that the store lacks in fields that otherwise name messages. This report separates these cases.

Anatomy of a unified-log record as read by this studyA synthetic record. Header: stream Persist, subsystem com.example.app, category notifications, process example daemon. Items: first item a public string holding a message identifier that is matched to a row in the Messages store; second item a private string shown as private and withheld; third item a public number. Arrows: the identifier is linkable, the private string is not.headerstream, time, subsystem / category, process imageitem 0: public string3F2504E0-4F89-11D3-9A0C-0305E82C3301matches a rowitem 1: private string<private>value withhelditem 2: public number7no identifierSynthetic values. A record is a call site plus its items;the format string is not read.
Figure 1: A unified-log record as this study reads it: a header with stream, time, subsystem, category and process image, and items. Only a public item can be compared with the store. Synthetic values.

The problem. Three things are unknown. First, how much of the Messages store the log names, and how that falls with age. Second, how many identifiers the log holds that the store does not, and whether they can be read as removed messages. Third, how much of the messaging components' own output redaction removes. Without them an examiner can neither rely on a log trace nor argue from its absence.

Approach. We read the unified log and the Messages store of every iOS full file system extraction in the Lab's research corpus that holds both, with our own reader, and compared the identifiers they contain. The study is observational: no message was sent, edited, unsent or deleted for it. We ask four research questions.

  • RQ1 (Coverage). How often does the log name a message that is in the store, in which components and streams, and at what age?
  • RQ2 (Orphans). How many message-like identifiers does the log hold that the store does not, and what else could explain them?
  • RQ3 (Deletion). Are messages that the store holds in Recently Deleted named in the log more often, or later, than other messages?
  • RQ4 (Redaction). What do the messaging components withhold, and what stays linkable?

Contributions. This report makes four contributions.

  • A measurement, on 27 iPhones and iPads, of how much of the Messages store the unified log names, by age, direction, service, component and stream (Sections 5.1 and 5.2).
  • A definition of an orphan identifier by the purity of its field, three tests of what else explains an orphan, and the resulting counts (Sections 3.5 and 5.3).
  • A test of the store's delete date as a measure of deletion time, and a comparison of messages in Recently Deleted with the other messages of the same devices (Sections 3.6 and 5.4).
  • Redaction counts for the messaging components and the components that name messages (Section 5.5), and a description of a kernel source that names message identifiers without being an event (Section 5.2).

Scope. The study describes what the logs and stores of 27 research devices contain. No marker experiment was run, so it cannot say what a given deletion leaves; a controlled replication on a test phone is future work. Counts are of identifiers, never of message content. Section 7 states the limits.

2 Background and Related Work

This section describes the unified log as evidence and what Apple says about its privacy, the Messages store and what is known about deleted messages, and the work closest to this study, and then states where this report stands.

2.1 The unified log and its privacy model

iOS writes one system-wide log through the unified logging system [7]. A record carries a time, the writing process, a subsystem and category chosen by the developer, a level, and a message built from a format string and its arguments; the archive stores the arguments and refers to the format string by an offset into the binary that wrote it. The records are kept in tracev3 files in directories for several streams (Persist, Special, Signpost, HighVolume) [14]. The format is not documented by Apple; the public description by Metz [17] and the open-source parser of Mandiant [16] are the references on which tools and this study rely.

Apple's documentation says that the privacy options of the logging interface decide whether a value in a message is redacted or shown, and that they exist so that sensitive information is hidden [8]. An Apple engineer describes the default in the developer forums: strings are private by default, a private value is omitted from the log, and tools show it as <private> [12]. Apple's security notes show that the handling is revised. The notes for iOS 26 describe one fix as a logging issue “addressed with improved data redaction” [10], and those for iOS 27 list two entries of the same kind, one for TCC and one “improved private data redaction for log entries” in a framework [11]. These statements say that redaction matters and changes; they do not say what is redacted for messages.

2.2 Retention and forensic use of the log

Practitioners agree that the log is short-lived and variable. Afonin reports that most entries have a short time-to-live and can expire within minutes or hours, and that a sysdiagnose mostly covers the day it was generated [6]. Korver compared archives made by a sysdiagnose and by the command line and reports about 2 and 14 days on an iPhone, without looking at individual processes or artefacts [15]. Notari publishes articles and a parser for iOS unified logs [18]. Open-source tools convert the log for analysis: the Sysdiagnose Analysis Framework [13] can call Mandiant's parser for the logarchive, and iLEAPP [1] bundles it; their README files list no analysis of message identifiers in the log (the artifact list of iLEAPP was not available to us). The Lab's own reports measured the retention horizon of the unified log among other stores [3], the clocks of the log [4], and which security controls leave a trace in it and what redaction withholds [2]. None looked at messages.

2.3 Deleted messages and the Messages store

Since iOS 16 a user can recover a deleted conversation or message for 30 to 40 days [9]. Rhodes reports from cases that recovery of deleted message content on newer iPhones is nearly impossible, that gaps in the sequential row numbers of the message table place a deletion between two neighbouring messages, that the counter of the table gives the total number of deletions, and that the table of deleted messages keeps its records only briefly [19]. SQLite does not reuse the numbers of deleted rows in an AUTOINCREMENT table, but numbers can be skipped [20]. What a deleted row leaves inside a database depends on secure_delete, vacuum and the journal mode [5]. All of this concerns the store itself. Whether the log, which is written by other components, carries identifiers of messages that are no longer in the store has, in what we found, not been measured.

2.4 Position of this work

We searched the practitioner and vendor sources above, the DFRWS and Digital Investigation material that web search reaches, and the ACM, IEEE, arXiv and Springer indexes for work on message identifiers in the iOS unified log, on how long they last, or on how redaction affects linking them. We found none. The expectation that logs may hold traces of deleted messages is, in what we found, untested. This report adds an observational measurement: how often the identifiers of messages in the store occur in the log, in which components, streams and ages, how many identifiers occur that the store does not hold and what explains them, and what redaction leaves linkable. The matching of identifiers is simple and is engineering; the measurement and the account of the false positives are the contribution. Retention is not the contribution; it has been measured before [3], [15]. No marker experiment was run, so the study cannot say what a given deletion leaves.

3 Method

The study has four parts: a frame of extractions that hold both a log and a Messages store, a reader for the log, a comparison of identifiers between the log and the store, and counts of what the log redacts (Figure 2). The reader and the comparison are our own code; nothing was parsed by a third-party tool.

Method: two inputs, one comparison, three outputsThe Messages database with its write-ahead log gives reference sets of identifiers. The tracev3 files of four streams are read by the study reader into values with their field. The comparison produces the positive control, the orphans with three tests, and the redaction counts.Messages store + WALsms.db and its WALtracev3 files, 4 streamsfour stream directoriesReference setsmessage, chat, attachment idsStudy readerchunks, catalog, itemsComparisonUUIDs against the setsPositive controlmessages in storeOrphansthree testsRedactionprivate item counts
Figure 2: Method: the store gives reference sets, the reader gives values with their field, and one comparison gives the positive control, the orphans and the redaction counts.

3.1 Frame

The frame is every iOS full file system extraction in the Lab's census of its research corpus on the drives attached at the time of the study. Extractions that were byte-identical copies, or a second extraction of one handset, were counted once. An extraction enters the analysis if it holds at least one tracev3 file and the Messages database. Sysdiagnoses and other packages that carry a log but no Messages store, and extractions without a log, are outside the frame.

3.2 Reading the log

We read the tracev3 files of the four log directories (Persist, Special, Signpost and HighVolume) with a reader written for this study from the public format description [17]. It decompresses each chunk set, reads the catalog for the subsystem and category of each record, and walks the log and signpost records of every firehose chunk. It does not resolve format strings, which would need the name files of the device. A record is therefore a call site, identified by its record type, strings-file type, image of the format string and 32-bit format reference, together with its items, the ordered arguments. A field is a call site together with an item position. The process that wrote a record is named from the image path in its name file. Oversize chunks, statedumps and simple dumps are searched as bytes. Time is taken from the pair of wall-clock and continuous time in the header of each file; where a header holds no valid wall clock (written before the clock was set), the pair of the nearest valid header of the same boot is used.

Items are of three kinds that matter here. A public string or binary item holds its value in the record. A private string item holds only a reference to a range of private data, which a chunk stores only when private data were recorded for it; otherwise the value is not in the file and tools print <private> [17]. A private scalar holds a masked number. We count all three, and read stored private values when a chunk holds them.

3.3 Identifier classes

The Messages store gives the reference sets, read from a copy of sms.db together with its write-ahead log: the GUID of each message; the GUIDs a message refers to (reactions, replies); chat group identifiers; attachment GUIDs; and tombstone GUIDs from the tables of messages the store itself records as deleted. We also take every UUID-shaped string that occurs anywhere in the bytes of the database and its write-ahead log, so that identifiers in free pages and in blobs are not mistaken for absent. A UUID-shaped string (36 characters, hexadecimal groups of 8-4-4-4-12) found in a public item, a stored private item, an oversize chunk, a statedump or a simple dump is compared case-insensitively with these sets. Phone numbers and e-mail addresses in public items are compared with the stored handles and counted, never kept. No message text is selected from the store; the bytes of the database are scanned only for UUID-shaped strings.

3.4 Positive control: messages that are in the store

A message that is in the store is a reference case: if the log carries identifiers of messages at all, it should carry those of messages the store holds. For each device we call a message eligible if it is a main message (not a reaction) dated inside the time span covered by the Persist stream, from its oldest chunk to the end of the log, and found if its GUID occurs in the log. We report the share found, by message age, direction, service, stream and field, and the delay between the message date and the first sighting. A secondary count uses the span of any stream. Messages dated before the span are counted separately.

3.5 Orphans: identifiers that are not in the store

An orphan is a UUID-shaped value in the log that is none of the stored identifiers. Most UUIDs in a log are not message identifiers, so an orphan must be restricted to fields where the values are message identifiers. A field is message-identifier if at least three distinct stored message GUIDs of the device occur in it; its purity is the number of distinct stored message GUIDs divided by that number plus the distinct unmatched UUIDs in the field. An orphan in the primary rule is an unmatched UUID in a field of purity at least 0.5 with at least five distinct stored message GUIDs; purities of 0.9 and 0.2 give sensitivity counts. A UUID that is a tombstone, a stored message GUID or any other stored identifier is never an orphan, because identifiers are classed against the store first. For the orphans of the primary rule we apply three tests of what else could explain them and report the count each removes: (a) last sighted in the final hour of the log, (b) first sighted more than an hour after the newest message in the store, so that the store may not yet hold it, and (c) found anywhere in the bytes of the store or its write-ahead log. The tests are not exclusive.

The tests do not cover other devices (a message processed here for an account's other device), edits and unsends, retention at the end of a stream, or a reset of the store. Section 7 states what follows from that.

3.6 Messages in Recently Deleted

The store keeps a message that was deleted from a conversation in a Recently Deleted state for a period before it removes it [9], and a join table links the message to a delete date. We call a message Recently Deleted if it has a row in that table or in the table of recoverable parts. The store does not record whether the user or a synchronised device deleted it. We first compare the delete date with the date of the message. If the delete date were the time of deletion, we could ask whether a message is named after it. We then compare, for Recently Deleted messages dated inside the Persist span, the share named in the log and the number named more than a minute, an hour and a day after the message date with the numbers expected for the other messages of the same devices. A deletion that made a component print the message's identifier would add sightings later than other messages have. The expected counts are the rates of the other messages of each device, once as they are and once matched on direction (received or sent). Edited and retracted messages are treated alike, with the store's edit and retraction times. These are counts of messages the store still holds; they are not messages removed from it.

3.7 Rules fixed before the final run

The frame, the eligibility rule, the purity thresholds, the three tests and the redaction counts were written down in a dated private note before the final run. The note followed a first run on twelve devices, which showed that the matching worked and that unfiltered orphans in message-identifier fields outnumbered messages; the purity rule and the use of the Persist span as the primary span were chosen then. The Recently Deleted comparison was added after a later full run and was changed when the delete date proved to equal the message date. Every number in this paper comes from one run of the final reader. No marker experiment was run: no message was sent, edited, unsent or deleted for this study.

4 Evidence and Setup

Sample. The Lab's census of its research corpus on the drives attached at the time lists 35 records of iOS full file system extractions. One is a byte-identical copy of another and one is a second extraction of a handset already listed; hash comparisons of device-unique identifiers (recorded in the Lab's private notes) show that the remaining 33 extractions are 33 different devices. Of these, 5 hold no unified log and 1 holds no Messages store, which leaves 27 devices (Table 1). One of them holds a store without messages, so 26 contribute messages. Extractions that are not in the census are not part of the sample. Sysdiagnoses and other log-only packages are outside the frame because they carry no store.

Table 1: From the census to the analysed devices.
StepDevices
iOS full file system records in the census35
Copy or second extraction of a listed device2
Different devices33
No unified log5
No Messages store1
Analysed (log and store)27
  with at least one message26
  with a message dated inside the Persist span19
  with at least one such message named in the log19

Composition. The 27 devices are 26 iPhones and 1 iPad (from the product type in the log headers) and run iOS or iPadOS 14 to 26: 20 on 26, 3 on 17 or 18, 3 on 15 or 16, and 1 on 14 (the census does not record its release; the build number in its log headers gives it). Their stores hold 1,702,179 message rows, a median of 21,129 per device (quartiles 3,762 to 52,948); 18 stores hold messages in Recently Deleted. The logs comprise 12,167 tracev3 files (18.9 GB) and 533.8 million tracepoints. The Persist stream covers a median of 6.4 days before the end of the log (quartiles 2.4 to 14.3, range 0.5 to 48.6); the Special stream a median of 25.7 days. Signpost files exist on 10 devices and HighVolume files on none.

Procedure. One runner script processed every extraction in its own process. It reads the ZIP central directory, copies sms.db and its write-ahead log to a scratch folder, reads the identifier sets with SQLite, reads each tracev3 file from the archive into memory and discards it after use, and writes one aggregate result file per device. The runner and the reader are written in Python with the standard library only; the reader follows a public format description [17] and no third-party tool was run. A check on a fixed random sample of up to three files per device found that all 4,889,795 log and signpost records parsed without error and that 0.65% of the string and binary items had a range outside their record, which the reader skips. Of 17.2 million firehose chunks, 403 further inner chunks carried an unknown tag and were skipped. The newest log record lay 0.4 to 8.5 hours before the end time recorded in the extraction's metadata on all 17 devices that have such a record.

5 Results

Table 2 maps each research question to its answer.

Table 2: Research questions and answers.
QuestionAnswer on these devicesSection
RQ1 Coverage24.3% of the 2,867 messages dated inside the Persist span are named (22.7% to 25.9%); 60% under a day, 0.1% at 7 to 14 days; received 32%, sent 11%. Names come from notification, Focus and sharing records.5.1, 5.2, Table 3, 4
RQ2 Orphans201 message-like identifiers the store lacks in 11 devices; 189 after three tests. Fields also carry other identifiers, so they are candidates, not removed messages.5.3, Table 5
RQ3 Deletion407 Recently Deleted messages in the span: 68 named (85 to 109 expected from other messages), 15 named after the first minute (23 to 24 expected). The delete date is the message date for 98%, so deletion time could not be tested.5.4, Table 6
RQ4 RedactionMessaging components withhold 54% of string items, others 18%; stored private values: none in the messaging components.5.5, Table 7

5.1 Messages in the store that the log names

The log names a quarter of recent messages. Of 2,867 main messages dated inside the Persist span of 19 devices, 696 (24.3%; Wilson 95% interval 22.7% to 25.9% [21], a pooled interval that treats messages as independent) had their GUID in a log record. The share differs between devices: among the 16 devices with at least ten such messages the median is 50% (quartiles 28% to 77%, range 6% to 100%). The share falls with age (Figure 3, Table 3): 60% of messages under a day old, 48% at 1 to 3 days, 18% at 3 to 7 days, and 1 of 818 at 7 to 14 days and 1 of 323 at 14 days or more. The oldest message named on a device was a median of 3.2 days old (maximum 18.9), although the Special stream spans a median of 25.7 days. Naming ends sooner than the streams do.

Table 3: Messages dated inside the Persist span and named in the log, by message age at the end of the log, direction, service and Recently Deleted state. Rows after the first block regroup the same messages.
GroupMessagesNamedShare
<1 d44426860.4%
1-3 d66131748.0%
3-7 d62110917.6%
7-14 d81810.1%
≥14 d32310.3%
All2,86769624.3%
Received1,83858231.7%
Sent1,02911411.1%
iMessage1,37647334.4%
SMS60914323.5%
RCS882809.1%
In Recently Deleted4076816.7%
Not in Recently Deleted2,46062825.5%
Share of eligible messages named in the log, by message ageHorizontal bars, share of messages dated inside the Persist span whose GUID occurs in the log: under 1 d 268 of 444 (60.4%); 1-3 d 317 of 661 (48.0%); 3-7 d 109 of 621 (17.6%); 7-14 d 1 of 818 (0.1%); at least 14 d 1 of 323 (0.3%).under 1 d60%268/4441-3 d48%317/6613-7 d18%109/6217-14 d0%1/818at least 14 d0%1/323share of messages named in the log
Figure 3: Share of messages dated inside the Persist span that are named in the log, by message age at the end of the log. Right: named over eligible. Source: runner report, positive control.

Received messages are named almost three times as often as sent ones (32% against 11%), iMessage more often than SMS and SMS more often than RCS (34%, 23%, 9%). Messages in Recently Deleted are named less often than others (17% against 26%); Section 5.4 compares them with the other messages of the same devices. The 696 named messages were named a median of 9 times (quartiles 4 to 30); 46 were named once. Counts by operating system release are too uneven to compare (Section 7).

5.2 Where, when and in which stream

The log names a message when a component that handles it for another purpose prints its GUID. Table 4 lists the components that named most of the 696 messages. The Focus-resolution records of SpringBoard (subsystem donotdisturb, category BehaviorResolution) named 441 of them and was the first to name 358; the transport records of imagent and identityservicesd, the notification pipeline and a suggestions daemon follow. Of the 696 named messages, 578 (83%) were first named within a minute of their date, 12 within the hour, 33 within a day and 73 later. The slow ones are a people-suggestion component (subsystem PeopleSuggester, process coreduetd; median 45 h) and a photo-sharing component (subsystem photos.backend, category Syndication, process assetsd). From the subsystem names we read these as acting on a message after it has arrived; we did not read the format strings.

Table 4: Components that name messages dated inside the Persist span: messages named by the component, messages for which it was the first, and the median delay between the message date and its first record.
Component (subsystem, category; process)NamedFirstMedian delay
Focus resolution (donotdisturb, in SpringBoard)4413581 s
Focus resolver (donotdisturbd)304490 s
Transport connection (imagent)111981 s
Transport daemon (identityservicesd)1100-
Notifications pipeline (SpringBoard)98102 s
Proactive harvesting (suggestd)66271 s
Telephony message centre (imagent)32320 s
UserNotificationsKit (SpringBoard)290-

By stream, 183 named messages appear only in Persist, 334 only in Special and 179 in both; Signpost files named none. The messaging daemons' own subsystems (Identity Services, Messages, MobileSMS and the CommCenter message category) printed none of the 205,658 message-GUID values (Section 5.5). A different kind of record names far more messages, but not as events. Records of the kernel contain the GUIDs of 31,634 messages dated before the Persist span that no other record names, on 7 devices, and, on three devices, tens of thousands of identifiers the store does not hold. We inspected the form of these records on one device only, where they are System Policy denial lines that name file paths under the Messages attachment folder; we did not inspect them on the other six. They name no message that was dated inside the span and not named elsewhere (0 of 696), so they add nothing to the coverage counts above; we did not test whether the files they list still exist.

5.3 Identifiers the store does not hold

20 devices have at least one message-identifier field, 270 fields in all. In the 101 of them with purity of at least 0.5 and five or more stored message GUIDs, 3,138 distinct values are stored GUIDs and 465 are not (a value in two fields counts in both). Under the primary rule 201 distinct unmatched UUIDs on 11 devices are orphans (Table 5, Figure 4). Three tests remove 4 (last sighted in the final hour), 4 (first sighted more than an hour after the newest stored message) and 7 (found in the bytes of the store). Tombstones are never orphans, because tombstone UUIDs are classed before orphans are formed. 189 remain on 10 devices. Of the primary orphans, 128 were seen only in the Special stream and 51 only in Persist; 23 were seen once and 9 over more than a day. The strictest rule (purity 0.9) leaves 12 of 14; the loosest (0.2) gives 60,460, of which the tests remove all but 1,682.

Table 5: Orphans by purity threshold and the effect of the tests: orphans, orphans last sighted in the final hour, orphans first sighted after the store's newest message, orphans found in the store's bytes, orphans that remain, and devices with a remaining orphan. The test columns overlap.
PurityOrphansFinal hourAfter storeIn bytesRemainDevices
0.914012125
0.5 (primary)20144718910
0.260,46035,75057,75238,4261,68216
Orphans under the primary rule and what the tests removeHorizontal bars, counts of distinct unmatched UUIDs: Orphans (0.5) 201; Final hour 4; After store ends 4; In store bytes 7; Remain 189. The three tests are not exclusive.Orphans (0.5)201Final hour4After store ends4In store bytes7Remain189distinct unmatched UUIDs
Figure 4: Orphans under the primary rule (purity at least 0.5) and the three tests; the test counts overlap. Source: runner report, orphans.

An orphan is not a removed message. The fields in which orphans fall also carry other identifiers: the pooled purity of the primary-rule fields is 87%, so about 13% of the UUIDs in these fields are not stored messages, and nothing in the log says how many of those are removed messages and how many are, for instance, notifications of other applications. The orphans come from the same components that name stored messages (Focus resolution 69, UserNotificationsKit 25, the transport connection of imagent 21, the suggestions component 15), which is the pattern either cause would give. The tests cover only some other causes (Section 3.5); messages seen here for another device, edits and unsends, and a reset of the store are untested. The count depends on the rule: 12 remain at purity 0.9, 189 at 0.5 and 1,682 at 0.2. For scale, the message counters of the stores exceed their message rows by 1,703,347 in 25 stores, of 3,405,526 message numbers issued; those numbers were consumed by deletion, by messages never stored, or by other causes [20]. Tombstone GUIDs, which the stores themselves record as deleted, occur in the log 140 times among 328,627 tombstones on 16 devices, on 4 of them. Reactions and replies refer to 193 messages that are not in the store, and the log names 19 of them.

5.4 Messages in Recently Deleted

The delete date of these messages is not a time of deletion that we can use. The 18 stores that have the join table hold 2,120 rows; for 2,008 of them (94.7%) the delete date lies within a second of the date of the message, for 61 within a minute and for 51 further away. Of the 407 Recently Deleted messages dated inside the Persist span, on 8 devices, 398 are within a second and all are within 8 seconds. Either the field is not the time of deletion or these messages were deleted on arrival, and we cannot tell which. A test of whether a message is named after it was deleted has no usable event, and we do not report one.

What the data do show is a comparison with the other messages of the same devices (Table 6). 68 of the 407 messages (16.7%) were named in the log, against 628 of 2,460 (25.5%) for the other messages. The other messages of the same eight devices would give 85 named messages, and 109 when matched on direction, because most Recently Deleted messages (363 of 407) were received. After the first minute 15 were named against 23 to 24 expected; after an hour 10 against 18 to 19; after a day none against 6 to 8. A deletion that made a component print the message's identifier would add late sightings, and there are fewer than expected. 5 edited messages lay inside the span: 3 were named and none after its edit time. No message with a retraction time lay inside the span.

Table 6: Messages in Recently Deleted dated inside the Persist span. Expected values give the count that the other messages of the same devices would have for the same number of messages: matched on device, and matched on device and direction.
CountObservedExpected, deviceExpected, device and direction
Recently Deleted messages dated inside the span407--
  named in the log6885109
  named more than 60 s after their date152324
  named more than an hour after their date101918
  named more than a day after their date086
Devices with at least one such message8--

This is not a deletion experiment. The messages are still in the store, the time of deletion is unknown, and whether a user or a synchronised device deleted them is not recorded. The comparison supports a negative statement only: on these devices a message in Recently Deleted was not named more often, or later, than the other messages. It cannot say what deleting a message does at the moment of deletion.

5.5 Redaction

Redaction withholds a larger share of what the messaging subsystems print than of what other subsystems print. Of their 4,050,630 string items, 53.5% are private and none is stored in a readable form, against 17.7% elsewhere (595,812 stored values among 128,264,428, 0.46%). Identity Services alone is 54% private and the Messages subsystem 58%. None of the 205,658 message-GUID values in the data occurs in the messaging subsystems. The subsystems in which message GUIDs do occur print mostly public strings (5.5% private): the identifier is public where a component handles a message for another purpose and private where the messaging daemons handle it for their own.

Table 7: String items of log and signpost records by subsystem group. Private items hold a reference to private data; stored ones are those whose value a chunk holds. The messaging group is fixed by subsystem name; the second group is the subsystems with at least one message GUID value, and overlaps the third. Columns count string items: public, private, private share, and private items whose value is stored.
GroupPublicPrivatePrivate shareStored
Messaging1,883,1912,167,43953.5%0
Naming messages3,808,704221,1855.5%0
All other595,000,414128,264,42817.7%595,812
Share of string items that are private, by subsystem groupHorizontal bars, private string items over all string items: Messaging 53.5%; Naming messages 5.5%; All other 17.7%.Messaging53.5%2,167,439Naming messages5.5%221,185All other17.7%128,264,428share of string items that are private
Figure 5: Private string items as a share of all string items of log and signpost records. Right: number of private items. Source: runner report, redaction.

What stays linkable is therefore the GUID in the notification, Focus and sharing records and, in the same records, the time of the message. Phone numbers and e-mail addresses that equal a stored handle occur in public strings 15,972 times; we did not attribute them to components. We cannot say whether the revision of redaction that Apple's security notes describe [11] changed any of this: 20 of the 27 devices run iOS 26, and they hold 2,588 of the 2,867 eligible messages.

6 Discussion

What the log can support. For a message that arrived in the last days before extraction, the log is a witness for about 24% of the messages, with the message's GUID and its time, written mostly by notification and Focus components within a minute of arrival in 83% of the cases. An examiner can use a hit to corroborate that a message existed at a time. Absence says little: 76% of recent messages are not named, and sent messages least of all.

What it cannot support. It cannot show that a message was removed. Messages in Recently Deleted were not named more often, or later, than others (Section 5.4), and the store's delete date could not be used as a time of deletion; the identifiers the store lacks number 12 to 1,682 after the tests, depending on how strictly a field must carry message identifiers, and sit in fields that also hold other identifiers (Section 5.3); and the oldest message the log names on a device is a median of 3 days old (at most 19), even where a stream reaches back weeks. A search of the log for the GUID of a message known to be removed is worth running, but a negative result is expected, and a positive one needs the tests of Section 3.5 before it is read as a trace of removal.

A caution on counting. The largest source of message GUIDs in the data is not an event record but kernel records that, on the one device where we inspected them, are denial lines that list attachment paths (Section 5.2). Counting every UUID that equals a stored GUID would have credited the logs with 33,454 messages older than the span, nearly all from that one source on a few devices. A study or a tool that reports identifiers found in a log without naming the record that holds them can overstate what the log retains.

Next to earlier results. The Persist span here (median 6.4 days, from the end of the log) is longer than the 2.5-day median horizon reported for other devices, measured back from the time of the extraction [3]; the measures differ, and Korver found 2 and 14 days for two collection methods [15]. The Lab's report on security controls found that the log mostly restates status and that redaction removes values [2]; the messaging subsystems withhold values in the same way. The store-side evidence of deletion that practitioners use, number gaps and counters [19], is far larger than anything the log holds: 1,703,347 numbers are missing from the stores against at most 1,682 candidate identifiers in the log under the loosest rule.

7 Threats to Validity

Internal validity. The reader is our own. A check on a fixed random sample of files found every log and signpost record parsed without error, which shows that the reader does not fail, not that it is right; against the format description and a published parser we checked the header, catalog, chunk and tracepoint layouts, the 16-byte header that the public data size counts, and the order of private strings, and 0.65% of the string and binary items were unreadable; activity and loss records, which carry no message items, were not read. A message GUID found is a 122-bit match and cannot arise by chance, so positive counts are specific; counts of absence are lower bounds, because GUIDs printed in another form (lower case is handled; hashed, truncated or embedded in binary structures are not) are missed. A field is a call site and an item position, not a format string, so two format strings from one call site share a field. Time is converted from the file header and not from the time-synchronisation database. The check against the end times in the extractions' metadata (Section 4) bounds its error to hours on 17 devices; that 83% of the named messages were first named within a minute of their date shows that log time and store dates agree to seconds where a message is named, and the check does not exclude a larger error elsewhere. Header clocks were borrowed from neighbouring files of the same boot for 7 files on 3 devices.

Construct validity. A message named in the log is a message whose GUID a record printed; it does not mean that the message was displayed or read. The message dates and the delete dates are those the store holds. An orphan is a UUID in a message-identifier field, and the purity thresholds (0.5 primary, 0.9 and 0.2 as sensitivity) were fixed after a pilot on twelve devices that showed orphans outnumbering messages in unfiltered fields (Section 3.7); the rule is a design choice and not a measurement. The tests do not cover other devices, edits, resets or retention at the edge of a stream, so orphans are candidates and not a lower bound of removals. A message is eligible if it is dated inside the Persist span, but records expire at different rates (Section 2.2), so the span overstates what the log still holds for any one component; the fall of the named share with age (Figure 3) mixes expiry with the behaviour of the components, and we do not separate them.

External validity. 27 devices of one corpus, 20 of them on iOS 26, are not a sample of phones in use; 16 devices contribute ten or more eligible messages and a few contribute most, so the pooled share counts messages and not devices. Releases other than 26 are too few to compare, and the share of recent messages is whatever the devices held. Components and their coverage may differ in other releases.

Conclusion validity. The intervals treat messages as independent although messages of one device share its components, so the pooled interval is narrower than a device-level one would be.

Limitations. No marker experiment was run; no message was created, edited, unsent or deleted for this study. The time of deletion is not known. Format strings were not resolved, so components are named by subsystem, category and process and nothing is said about what a record states. Hashed or masked identifiers were not searched. A store restored from a backup or synchronised from another device is not told apart. Third-party applications were not examined.

8 Conclusion and Future Work

We asked whether removed messages leave traces in the iOS unified log, and measured what the log holds about messages that are still in the store, which is the reference for any trace. On 27 research devices the log named 24% of the messages dated inside the Persist span, nearly all within a minute of arrival and almost none after the first week, through the notification, Focus and sharing components rather than the messaging daemons, whose own records withhold 54% of their strings. Messages in Recently Deleted were named no more often and no later than other messages, although the time of deletion could not be tested, and the identifiers that the store does not hold are few and sit among other identifiers, so they cannot be read as removed messages. On these devices the log can corroborate that a recent message existed; it did not show that one was removed.

Future work, in order of value: (1) a controlled replication on a test phone, in which messages with known identifiers are sent, edited, unsent and deleted at recorded times and the log is captured at once, to turn the candidates of Section 5.3 into measured detection rates; (2) resolving the format strings of the leading components, to say what each record states and which fields carry message identifiers by construction; (3) reading the kernel records on every device and testing whether the files they list still exist, which would turn that source into evidence of file-system residue; (4) a pair of releases on one device, to measure the effect of changes in redaction.

Artifact Availability

The reader, the analyser, the script that aggregates the result files, a generator of a synthetic extraction with planted counts, the reader tests and a reproduction guide will be released in the Lab's public artifacts repository, with no release date set (code MIT licence; data and text CC BY 4.0). The package is not public yet, and the sentences that follow describe it as planned. They use only the Python standard library. The synthetic run reproduces the layout and the logic of Tables 3, 5 and 6 with synthetic values, which show the shape of the tables and not the findings. The synthetic files are written from the same public format description as the reader, so the tests show that the two agree, not that Apple's files follow the description. The tables with corpus values cannot be reproduced from the package: the extractions, the census that lists them and the per-device result files, which hold names taken from the logs, are kept by the Lab and are not released.

Data Handling Statement

The evidence for this study is drawn from the Lab's research corpus of mobile device extractions and was read only. The runner read the unified-log files, the Messages database with its write-ahead log, the image-path footers of the log's name files and, for a clock check, the end time in the extraction's metadata file. The report gives aggregate counts, shares, device classes and operating system releases. It contains no identifiers, personal data, message or file content, or case information. Identifiers from the Messages store were compared in memory and were not written to any result file. The Lab's private per-device result files hold the subsystem and category names and statedump titles that the log carries, some of which embed identifiers, and are not published. The runner did not select the text of any message from the store. The identifier in Figure 1 is a synthetic value, and the example files released with this report contain only synthetic data.

Declaration of AI Assistance

The authors conceived the research questions and directed the work. The measurement code, the data checks and the first draft of this report were produced with AI assistance (Anthropic Claude). The authors reviewed the results and the text and are responsible for the content.

References

  1. abrignoni (GitHub organisation). [n. d.]. iLEAPP: iOS Logs, Events, And Plist Parser. GitHub repository (MIT). Retrieved October 29, 2026 from https://github.com/abrignoni/iLEAPP
  2. Daniel Addai, Sanders Larweh Tetteh, Selorm Adjabeng, and Kingsley Albert Egyir. 2026. What the iOS Unified Log Says About Device Security Controls: Most Leave a Trace, Few Record a Change. Lab Technical Report LAB-TR-0012, version 1.0. SectraTEK Lab, Prudential Associates. Preprint, not peer reviewed. https://lab.sectratek.com/research/reports/lab-tr-0012/
  3. Daniel Addai, Sanders Larweh Tetteh, Selorm Adjabeng, and Kingsley Albert Egyir. 2026. Retention Horizons of Volatile Stores in iOS and Android Extractions. Lab Technical Report LAB-TR-0021, version 1.0. SectraTEK Lab, Prudential Associates. Preprint, not peer reviewed. https://lab.sectratek.com/research/reports/lab-tr-0021/
  4. Daniel Addai, Selorm Adjabeng, Kingsley Albert Egyir, and Sanders Larweh Tetteh. 2026. Most Ordinary Phones Trip a Naive Clock-Anomaly Check: Base Rates of Clock Anomalies in Unselected Mobile Extractions. Lab Technical Report LAB-TR-0022, version 1.0. SectraTEK Lab, Prudential Associates. Preprint, not peer reviewed. https://lab.sectratek.com/research/reports/lab-tr-0022/
  5. Daniel Addai, Kingsley Albert Egyir, Sanders Larweh Tetteh, and Selorm Adjabeng. 2026. Zeroed Cells, Kept Pages, Pending Logs: What SQLite Leaves of a Deleted Row on 47 iOS and Android Devices. Lab Technical Report LAB-TR-0023, version 1.0. SectraTEK Lab, Prudential Associates. Preprint, not peer reviewed. https://lab.sectratek.com/research/reports/lab-tr-0023/
  6. Oleg Afonin. 2025. Extracting and Analyzing Apple sysdiagnose Logs. ElcomSoft blog, 27 June 2025. Retrieved October 29, 2026 from https://blog.elcomsoft.com/2025/06/extracting-and-analyzing-apple-unified-logs/
  7. Apple Inc. [n. d.]. Logging. Apple Developer Documentation, framework os. Retrieved October 29, 2026 from https://developer.apple.com/documentation/os/logging
  8. Apple Inc. [n. d.]. OSLogPrivacy. Apple Developer Documentation, framework os. Retrieved October 29, 2026 from https://developer.apple.com/documentation/os/oslogprivacy
  9. Apple Inc. [n. d.]. Recover deleted text messages on your iPhone or iPad. Apple Support article 102615. Retrieved October 29, 2026 from https://support.apple.com/102615
  10. Apple Inc. 2025. About the security content of iOS 26 and iPadOS 26. Apple Support article 125108 (entry for Bluetooth, released 15 September 2025). Retrieved October 29, 2026 from https://support.apple.com/en-us/125108
  11. Apple Inc. 2026. About the security content of iOS 27 and iPadOS 27. Apple Support article 149034 (entries for TCC and Symptom Framework, released 14 September 2026). Retrieved October 29, 2026 from https://support.apple.com/en-us/149034
  12. Apple Developer Technical Support (Quinn “The Eskimo!”). 2022. Recording Private Data in the System Log. Apple Developer Forums, thread 705810, posted 12 May 2022, revised 10 June 2023. Retrieved October 29, 2026 from https://developer.apple.com/forums/thread/705810
  13. EC-DIGIT-CSIRC. [n. d.]. sysdiagnose: Sysdiagnose Analysis Framework. GitHub repository (EUPL-1.2). Retrieved October 29, 2026 from https://github.com/EC-DIGIT-CSIRC/sysdiagnose
  14. Alexander Holcomb. 2022. Reviewing macOS Unified Logs. Mandiant, Google Cloud Blog, 31 August 2022. Retrieved October 29, 2026 from https://cloud.google.com/blog/topics/threat-intelligence/reviewing-macos-unified-logs/
  15. Tim Korver. 2025. Apple Unified Log vs sysdiagnose: retention compared. Thesis Friday #7, 29 May 2025. Retrieved October 29, 2026 from https://thesisfriday.com/thesis-friday-7-apple-unified-log-or-sysdiagnose/
  16. Mandiant. [n. d.]. macos-UnifiedLogs: a Rust library that parses the macOS Unified Log files. GitHub repository (Apache-2.0). Retrieved October 29, 2026 from https://github.com/mandiant/macos-UnifiedLogs
  17. Joachim Metz. [n. d.]. Apple Unified Logging and Activity Tracing formats. In dtformats, libyal documentation (asciidoc). Retrieved October 29, 2026 from https://github.com/libyal/dtformats
  18. Lionel Notari. [n. d.]. iOS Unified Logs Investigation: Digital Forensics by Lionel Notari. Web site with articles, tools and references. Retrieved October 29, 2026 from https://ios-unifiedlogs.com (Home page read; the articles were not read.)
  19. Alyssa Rhodes. 2023. Forensic challenges and solutions with the new iPhone Message Deletion. Vestige, 13 June 2023. Retrieved October 29, 2026 from https://www.vestigeltd.com/resources/articles/forensic-challenges-and-solutions-with-the-new-iphone-message-deletion/
  20. SQLite Consortium. [n. d.]. SQLite Autoincrement. Retrieved October 29, 2026 from https://www.sqlite.org/autoinc.html
  21. Edwin B. Wilson. 1927. Probable inference, the law of succession, and statistical inference. Journal of the American Statistical Association 22, 158 (1927), 209–212. https://doi.org/10.1080/01621459.1927.10502953 (Bibliographic data from index records.)

Cite and download

Cite as

Daniel Addai, Selorm Adjabeng, Kingsley Albert Egyir, and Sanders Larweh Tetteh. 2026. Residual Traces of Removed Messages in the iOS Unified Log: An Observational Study. Lab Technical Report LAB-TR-0013, version 1.0. SectraTEK Lab, Prudential Associates. Preprint, not peer reviewed. https://lab.sectratek.com/research/reports/lab-tr-0013/

Citation guide
lab-tr-0013.bib
@techreport{addai2026labtr0013,
  author      = {Addai, Daniel and Adjabeng, Selorm and Egyir, Kingsley Albert and Tetteh, Sanders Larweh},
  title       = {Residual Traces of Removed Messages in the iOS Unified Log: An Observational Study},
  institution = {SectraTEK Lab, Prudential Associates},
  type        = {Lab Technical Report},
  number      = {LAB-TR-0013},
  year        = {2026},
  howpublished = {https://lab.sectratek.com/research/reports/lab-tr-0013/},
  note        = {Version 1.0, preprint, not peer reviewed. CC BY 4.0}
}

Licence: CC BY 4.0. The print layout of this page is set for US Letter in two columns. Related: the Lab's reports on security-control traces in the unified log, LAB-TR-0012, and on retention horizons, LAB-TR-0021.

Versions and corrections

VersionDateChange
1.02026-10-29First release.

Corrections: none so far. Errors can be reported through the corrections page.