Are spam samples shared across users?

Issue Description

We have the following accounts configured:

user1 - real user and admin
user2 - real user and admin
shared group - group, shared between user1 and user2
test - real user without other privileges

When user1 accesses the “Spam samples” section they see samples gathered from user1 INBOX and user2 INBOX (!) and group INBOX. User2 see exactly the same samples. If both users choose “shared group” from the top-right menu the samples don’t change, they always see all. This is bad because each user has access to some of the private email of the other user (shared group email are obviously OK).

Fortunately enough this happens only for administrators: the test user does not see anything.

Expected Behavior

I expect user1 to see as samples only their emails and to see share group emails only when selecting the group from the top-right menu. I also expect to NOT see user1 emails after selecting the shared group.

I definitely don’t expect user2 to see user1 private emails and vice-versa.

Actual Behavior

See Issue Description.

Reproduction Steps

Configure Stalwart with the example accounts as described in Issue Description.

Relevant Log Output

None

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

This matches a real behavior in the current code, not something documented as intentional. Looking at how the “Spam samples” query is resolved server-side (spam_sample_query in the registry mapping):

  • If the account making the request has the Impersonate permission (which admin accounts have by default) and the query does not include an explicit accountId filter, the query falls back to fetching training samples across all accounts (greater_than_or_equal(Property::AccountId, 0)), rather than being scoped to the account/group currently selected in the top-right menu.
  • Only when an explicit accountId filter is present in the request does the result get scoped to that specific account/group.
  • Non-admin accounts don’t have Impersonate, so their queries are always forced to their own account_id, which is why the test user only sees their own samples.

So the behavior you’re seeing (user1/admin seeing samples from user2’s INBOX and the shared group all mixed together, with no change when switching the account selector) lines up with the admin/superuser path not being properly scoped by the currently-selected account context. This does look like unexpected cross-account exposure for admin accounts rather than intended design, since the docs only describe training samples as being tied to a specific account (see the SpamTrainingSample object reference). A staff/human follow-up will be needed to confirm whether this is a bug in the WebUI (not sending the account filter) or in the query fallback logic, and to address the fix.

Reference: SpamTrainingSample | Stalwart

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

Given that the problem is real and Stalwart is leaking private information cross-account it is possible to con vert this to a real issue on GitHub?

The training corpus is server-wide, and who can see it keys on the impersonate permission, which the default superuser role carries, which is why your two admins see everything while the test user sees only its own samples.

It is not an escalation path, though: any account holding impersonate can already open any mailbox on the server directly, so the samples expose nothing that account could not already read. If you have people who should administer the server without reading other users’ mail, the fix is a custom role that omits impersonate (or just the spam training sample permissions).