Skip to content

Commit 8f0f8c6

Browse files
Added docs for exposure report (#9133)
* Added docs for exposure report * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <[email protected]> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <[email protected]> * Minor fixes --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]>
1 parent ac56ddd commit 8f0f8c6

1 file changed

Lines changed: 94 additions & 3 deletions

File tree

source/administration-guide/manage/admin/content-flagging.rst

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Reviewers can select **View details** to take action as follows:
8888
- **Keep message**: Dismiss the quarantine and restore the message if it was hidden. The status of the quarantined message changes to **Retained**.
8989
- **Add a comment**: Record the reason for the decision when required.
9090
- **Generate a report**: Download a report of the quarantined message and review activity for record-keeping or incident response. See :ref:`administration-guide/manage/admin/content-flagging:generate a quarantined message report` for details.
91+
- **Download exposure report**: Download a report of the users who may have been exposed to the quarantined message while it was visible in its channel. See :ref:`administration-guide/manage/admin/content-flagging:generate a post exposure report` for details.
9192

9293
Once an action is taken, the **Status** field updates automatically. The **Data Spillage Bot** sends follow-up notifications to the reporter, author, and other reviewers based on how Data Spillage Handling is configured.
9394

@@ -106,15 +107,15 @@ If you choose to skip the report download from the **Remove message** or **Keep
106107

107108
If report generation fails (for example, due to a network interruption or session timeout), the dialog displays an error and offers a retry option. You can also skip the report and proceed with the action, or cancel and download the report later from the message details.
108109

109-
Each time a reviewer generates a report, the **Data Spillage Bot** notifies all content reviewers so an auditable record exists whenever a copy of the potentially spilled data is obtained.
110+
Each time a reviewer generates a quarantined message report or a :ref:`post exposure report <administration-guide/manage/admin/content-flagging:generate a post exposure report>`, the **Data Spillage Bot** notifies all content reviewers so an auditable record exists whenever a copy of the potentially spilled data is obtained.
110111

111112
.. tip::
112113
We recommend generating a report before removing a message. Once a message is removed, its content, attachments, and edit history are permanently deleted and can't be recovered.
113114

114115
Report contents and format
115116
^^^^^^^^^^^^^^^^^^^^^^^^^^
116117

117-
Each report is a ZIP archive containing YAML metadata files and the original file attachments. YAML is used because it's both human-readable and machine-parseable, which makes the report suitable for manual review and for ingestion by downstream compliance or incident-response tooling.
118+
Each quarantined message report is a ZIP archive containing YAML metadata files, a CSV exposure report, and the original file attachments. YAML is used for the metadata files because it's both human-readable and machine-parseable, which makes the report suitable for manual review and for ingestion by downstream compliance or incident-response tooling. The exposure report is CSV so that reviewers can open it directly in a spreadsheet.
118119

119120
The archive has the following structure:
120121

@@ -123,6 +124,7 @@ The archive has the following structure:
123124
/
124125
├── report_metadata.yaml
125126
├── content_review.yaml
127+
├── exposure_report.csv
126128
├── post/
127129
│ ├── post.yaml
128130
│ └── attachments/
@@ -133,14 +135,103 @@ The archive has the following structure:
133135
└── attachments/
134136
└── <original attachment files>
135137
136-
- **report_metadata.yaml**: Identifies the report itself, including the user ID and username of the reviewer who generated the report, the generation timestamp, and the report format version (used for forward compatibility if the report format changes in future releases).
138+
- **report_metadata.yaml**: Identifies the report itself, including the user ID and username of the reviewer who generated the report, the generation timestamp, and the report format version (used for forward compatibility if the report format changes in future releases). Report format version 1.1 added ``exposure_report.csv`` to the archive.
137139
- **content_review.yaml**: Captures the data spillage event, including the reporter's user ID, username, selected reason, and comment; the report timestamp; whether the message was hidden during review; and, once the quarantine is resolved, the reviewer's user ID, username, comment, and action timestamp. For unresolved quarantines, reviewer fields are omitted.
140+
- **exposure_report.csv**: Lists the users who may have been exposed to the quarantined message while it was visible in its channel. This is the same report that reviewers can download on its own, in the same format. See :ref:`administration-guide/manage/admin/content-flagging:exposure report contents` for the columns and how to interpret them.
138141
- **post/post.yaml**: Describes the quarantined message, including the post ID, author ID, author name, author email, message content, channel ID, channel display name, team ID, team display name, creation and update timestamps, pinned status, root ID, post properties, post metadata, reply count (for root posts), and the ordered list of edit history post IDs.
139142
- **post/attachments/**: The original files attached to the quarantined message, included verbatim.
140143
- **edit_history/<edit_post_id>/**: One subdirectory per previous version of the message, each containing a ``post.yaml`` and an ``attachments/`` directory in the same format as the base post directory.
141144

142145
To avoid duplication, attachment files are deduplicated across the entire archive by their file ID. Each unique attachment appears exactly once — under the base post if it exists in the current version of the message, or under the earliest edit-history entry that referenced it.
143146

147+
Generate a post exposure report
148+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
149+
150+
From Mattermost v11.11, reviewers can generate a post exposure report: a CSV file listing the users who may have been exposed to a quarantined message while it was visible in its channel. The report helps a reviewer scope the impact of a potential data spill and decide who needs follow-up.
151+
152+
.. important::
153+
154+
A post exposure report identifies who *may* have been exposed to a quarantined message. It isn't evidence that anyone read the message.
155+
156+
- The report is derived from channel membership history and from channel read timestamps. Neither records whether a message was ever displayed on screen.
157+
- A **Last viewed channel at** timestamp after the message was posted means the user opened the channel while the message was visible. It doesn't mean the message was displayed to them, or that they read it.
158+
- The report doesn't cover every path by which a message can reach someone. Push and email notifications can deliver message content to a user who never opens the channel, and content in a public channel can be reached without joining it.
159+
- Treat the report as a starting point for investigation, not as the sole basis for a compliance or disciplinary finding.
160+
161+
See :ref:`administration-guide/manage/admin/content-flagging:exposure report limitations` for what the report can and can't establish.
162+
163+
A post exposure report can be obtained from either of the following entry points:
164+
165+
- **From the quarantined message details**: Select **View details**, then select **Download exposure report** in the **Exposure report** row. The file downloads as ``post-exposure-<post_id>-<timestamp>.csv``.
166+
- **From the quarantined message report**: The ZIP archive produced by **Download report** includes the same data as ``exposure_report.csv``.
167+
168+
Only content reviewers can generate a post exposure report.
169+
170+
Exposure report contents
171+
^^^^^^^^^^^^^^^^^^^^^^^^
172+
173+
Every row in the report is one user who was a member of the channel at some point between the message being posted and the message being quarantined, taken from channel membership history. That row set is the complete population of users who could have been exposed through channel membership. It isn't the complete population of users who could have been exposed by any means.
174+
175+
The report doesn't produce a separate list of users who probably saw the message. Instead, every row carries the channel read state and account activity timestamps needed to judge likelihood, so reviewers triage a single table by sorting and filtering rather than reconciling two overlapping lists.
176+
177+
Report metadata is written as ``#``-prefixed comment lines above the header row, so the file describes itself without a separate metadata file. Most tools can skip these lines — for example, Go's ``csv.Reader`` with ``Comment: '#'``, or pandas with ``comment='#'``.
178+
179+
.. code-block:: text
180+
181+
# Report version: 1.0
182+
# Post ID: 8xk3mq7pzjfytr4wn6hb2dcvse
183+
# Channel: Engineering (jr9v2thq5xkfcm8bwd63pnysa4)
184+
# Post created at: 2026-07-14T09:12:03Z
185+
# Flagged at: 2026-07-14T11:48:37Z
186+
# Generated at: 2026-07-14T12:05:19Z
187+
# Total users: 3
188+
User ID,Username,Email,Guest,Remote user,Deactivated,Was channel member,Last viewed channel at (YYYY-MM-DDTHH:MM:SSZ),User last activity time (YYYY-MM-DDTHH:MM:SSZ)
189+
4tqzn8mhs2xdwc7bkgv6yrfpj3,alice.chen,[email protected],No,No,No,Yes,2026-07-14T10:31:52Z,2026-07-14T11:59:08Z
190+
mw6cbyx9rntk3f7zqhdps2gjv5,bhavna.rao,[email protected],No,No,No,Yes,2026-07-02T16:20:44Z,2026-07-14T12:01:44Z
191+
zd7pfk2vqn6ymxb3wcjs9htgr8,carlos.mendes,[email protected],No,No,Yes,Yes,Unknown,No sessions found
192+
193+
**Post created at** and **Flagged at** bound the reporting window that membership is resolved against. **Total users** is the number of rows in the file, counted after any users whose account records no longer exist are skipped.
194+
195+
The report includes the following columns:
196+
197+
- **User ID**: The system identifier for the user.
198+
- **Username**: The user's Mattermost username.
199+
- **Email**: The user's email address.
200+
- **Guest**: ``Yes`` if the user is a guest account.
201+
- **Remote user**: ``Yes`` if the user belongs to a remote server through a shared channel. Content on a remote server is beyond the reach of hiding or removing the message locally.
202+
- **Deactivated**: ``Yes`` if the user's account is deactivated. Deactivating a user doesn't undo their exposure, so deactivated accounts are still reported.
203+
- **Was channel member**: Always ``Yes`` in report version 1.0. Every row is a channel member by definition, and the column is reserved for future report versions that may add other exposure paths.
204+
- **Last viewed channel at (YYYY-MM-DDTHH:MM:SSZ)**: The user's *current* last-viewed timestamp for the channel, not a snapshot taken when the message was quarantined. ``Unknown`` means no read state exists because the user is no longer a channel member. ``N/A`` means the user is a member who has never opened the channel.
205+
- **User last activity time (YYYY-MM-DDTHH:MM:SSZ)**: The user's most recent session activity anywhere in Mattermost, not in this channel. ``No sessions found`` means no session records exist for the user, which is always the case for deactivated accounts.
206+
207+
To scope who needs follow-up, compare each row's **Last viewed channel at** value against the **Post created at** value in the report metadata:
208+
209+
- **At or after Post created at**: The user opened the channel while the message was visible. This is a possible exposure, and should be prioritized for follow-up.
210+
- **Before Post created at**: The user was a channel member, but hadn't opened the channel since before the message was posted. Exposure in the channel is less probable, but not ruled out — the message content may still have reached the user through a push or email notification.
211+
- **Unknown or N/A**: No channel read state exists for the user. Exposure is undetermined. Don't read these values as confirmation that the user didn't see the message.
212+
213+
.. tip::
214+
Generate the exposure report early in the review. **Last viewed channel at** reflects live channel read state, so it moves whenever a user opens the channel again, including after the quarantine is resolved.
215+
216+
Rows are sorted by username, then by user ID, so row order is the same every time the report is generated. The cell values aren't: **Last viewed channel at** and **User last activity time** both reflect live state, so two reports generated at different times can differ. Column headings and values, including ``Yes``, ``No``, ``Unknown``, ``N/A``, and ``No sessions found``, are localized to the language of the reviewer who generated the report. Downstream tooling shouldn't match on the English strings.
217+
218+
Exposure report limitations
219+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
220+
221+
The report is derived from channel membership history and channel read state, which constrains what it can establish:
222+
223+
- **Notification delivery isn't covered**: A user can be exposed to message content without ever opening the channel. Push and email notifications can include the message text, depending on your :ref:`push notification contents <administration-guide/configure/site-configuration-settings:push notification contents>` and :ref:`email notification contents <administration-guide/configure/site-configuration-settings:email notification contents>` settings. Notifications aren't reflected in the report, so an early **Last viewed channel at** value doesn't rule out exposure.
224+
- **Access to public channels without membership isn't covered**: The report lists channel members only. In a public channel, a message can also reach users who never joined the channel — through a :doc:`post permalink preview </end-user-guide/collaborate/share-links>` rendered when a link to the message is shared in another channel, or through search when :ref:`searching public channels without membership <administration-guide/configure/environment-configuration-settings:allow searching public channels without membership>` is enabled. None of these users appear in the report.
225+
- **Bots are excluded**: Bot accounts are omitted from the report.
226+
- **Users who joined after the message was quarantined are excluded**: Membership is resolved against the reporting window only.
227+
- **Users who left and rejoined appear once**: The report is a list of users, so multiple membership periods are collapsed into a single row. Individual join and leave times aren't reported.
228+
- **Users who left and didn't rejoin are included**: They're reported with **Last viewed channel at** set to ``Unknown``, because no channel read state survives for a former member.
229+
- **Guests and remote users are included**: Both are identified in their own columns.
230+
- **Archived channels are supported**: Members of an archived channel are reported as usual.
231+
- **Deleted accounts are omitted**: If a user's account record no longer exists, that user is skipped, and **Total users** reflects the count after the skip.
232+
233+
Generating an exposure report queries session activity for each user in the report individually, and the whole report is assembled in memory before the download starts. On channels with several thousand members, expect generation to take proportionally longer.
234+
144235
Deleted messages
145236
~~~~~~~~~~~~~~~~
146237

0 commit comments

Comments
 (0)