Skip to content

[WIP] MSC4284: Policy Servers #4284

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

turt2live
Copy link
Member

@turt2live turt2live commented Apr 7, 2025

Rendered

Disclosure: I am Director of Standards Development at The Matrix.org Foundation C.I.C., Matrix Spec Core Team (SCT) member, employed by Element, and operate the t2bot.io service. This proposal is written and published as a Trust & Safety team member allocated in full to the Foundation.

@turt2live turt2live added proposal A matrix spec change proposal kind:core MSC which is critical to the protocol's success needs-implementation This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP. safety labels Apr 7, 2025
@turt2live turt2live changed the title [WIP] MSC4284: Placeholder [WIP] MSC4284: Policy Servers Apr 16, 2025
@turt2live turt2live added s2s Server-to-Server API (federation) client-server Client-Server API proposal A matrix spec change proposal and removed proposal A matrix spec change proposal labels Apr 16, 2025
@@ -0,0 +1,188 @@
# MSC4284: Policy Servers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally this MSC in its current state is proposing something that sounds like the reverse of a recent idea in Draupnir of extending the API as to allow the easy creation of external protections. But this MSC instead proposes an API for calling into a Evaluator over fed.

I personally think this sounds like a great idea as this approach allows the maintainence of the philosophy of letting homeservers focus on being homeservers and farms out moderation to dedicated tooling that is fit for purpose. This is great for not only extensibility but also maintainability of these capabilities.

Draupnir has recently started to venture into this direction a tiny bit via its HS Admin Capabilities and Synapse module. This shows theres definetively an appatite for this type of capabilitity in the ecosystem. I have also seen wishes for this exact type of MSC expressed recently.

The request body is *optional* but *strongly recommended* for efficient processing, as the policy
server may not make efforts to locate the event over federation, especially during `/check`.

Authentication is achieved using normal [Federation API request authentication](https://spec.matrix.org/v1.14/server-server-api/#request-authentication).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is routing to the server subject to the normal federation server name resolution stuff (https://spec.matrix.org/v1.14/server-server-api/#resolving-server-names) ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would assume it makes sense to extend delegation in this MSC if we are using the normal server name stuff.

Since if the CS API can be separated it would make sense if this can also be separate but ofc using a separate subdomain always works as the MSC shows as an example.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is routing to the server subject to the normal federation server name resolution stuff (https://spec.matrix.org/v1.14/server-server-api/#resolving-server-names) ?

Yes - it's intended that the server participates in the room, but may not implement the full suite of federation endpoints.

Comment on lines +79 to +81
For Synapse homeservers, the above paragraph's consequences are natural behaviour of the spam checker
module feature. A server could, with some performance penalty, deploy a module which calls the `/check`
API to enact the consequences described above.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Provided `policy.example.org` is in the room, that server receives events as any other homeserver
in the room would, *plus* becomes a Policy Server. If `policy.example.org` is not in the room, the
assignment acts as though it was undefined: the room does not use a policy server.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing something obvious, but why is the policy server required to be a Matrix server that is participating in the room?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also appears to contradict the earlier statement: "This may be an existing logical server, such as matrix.org, or a dedicated host which serves no other purpose."

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Johennes My understanding of that sentence is simply that the /check endpoint may be implemented by an existing homeserver domain, or by a dedicated homeserver domain that doesn't provide any other Matrix functionality.

policy server ahead of sending their event(s). For example, `matrix.example.org` may have a user in
the room with permission to send redactions and `/check`s all events.

## Potential issues
Copy link

@CobaltCause CobaltCause Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be worried about situations in which this MSC is in use in a room but not implemented in all HSs participating in that room, as the following could happen:

  1. all room moderators are on HSs that implement this MSC
  2. abuse content is sent to the room by abusive users
  3. moderators do not see these users or their content
  4. thus moderators don't redact the content and ban the users
  5. thus users on HSs that don't implement this MSC will still see the abuse content

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly this could be mitigated by having draupnir (or another moderation bot) also make requests to the policy server, and then redact events. You might see abuse content temporarily that way if your HS doesn't implement this MSC, but it may be better than nothing.

Important note about this is that the moderation bot would need to run on a server that does not soft-fail events based on the policy server, otherwise it wouldn't be able to see the events it needs to redact.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important note about this is that the moderation bot would need to run on a server that does not soft-fail events based on the policy server, otherwise it wouldn't be able to see the events it needs to redact.

Perhaps there should be a way to opt-in to receiving soft-failed events as a client, so that moderation tools can still view and send redactions for abuse content and such. Such functionality would feel less hacky than making sure to run moderation tools on an HS that doesn't support this MSC.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're currently experimenting with having this done at the server level, via https://github.com/element-hq/policyserv_spam_checker for now

element-hq/synapse#18238 is another early example of experimentation in this area

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It kind of feels conceptually that each server should be able to redact events for their users only. This is in keeping with Matrix's server autonomy. Mod/admin servers can still redact which will still be broadcast to all other servers, but really whether this is applied is a per-server decision.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kegsay Such a design could also help prevent existing quirks, like DM conversation partners being able to unilaterally delete all conversation participants' messages.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Servers which use the policy server should be rejecting the events before they're sent to the room, instead of redacting them. A server could feasibly redact instead of send, but then it's just wasted events which may be further against room policy (flooding, "apparent malicious redaction", etc).

Comment on lines +169 to +175
An alternative was considered where, in a future room version, all events must be signed by the policy
server before they're able to be added to the DAG. However, this results in compulsory centralization
and usage, removing the room's agency to choose which moderation tools they utilize and that room's
ability to survive network partitions. This alternative does have an advantage of reducing bandwidth
spend across the federation (as there's no point in sending a spammy event if the policy server won't
sign it), but would require that communities upgrade their rooms to a compatible room version, which
typically take significant time to specify and deploy.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can still be added as an optimization - servers MAY get a signature from the policy server before sending an event to the room, which would allow other servers to skip the policy server check when receiving the event.

This may be an existing logical server, such as matrix.org, or a dedicated host which serves no other
purpose.

Rooms which elect to use a policy server would do so via the new `m.room.policy` state
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bikeshedding: not a fan of m.room.policy as a state event name, it's too generic. Maybe something like m.room.event_filtering?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The terminology also would otherwise conflict with the widely used "policy lists"

Comment on lines +71 to +73
If a policy server is in use by the room, homeservers SHOULD call the `/check` API defined below on
all locally-generated events before fanning them out and on all remote events before delivering them
to local users. If the policy server recommends treating the event as spam, the event SHOULD be soft

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an escape hatch, should the homeserver accept events recognised as coming from a room admin without a policy check?

(Maybe even allow a room admin to set a threshold, so that a moderation bot can operate directly, while letting the admins to remove the bot with a normal kick)

Comment on lines +169 to +172
An alternative was considered where, in a future room version, all events must be signed by the policy
server before they're able to be added to the DAG. However, this results in compulsory centralization
and usage, removing the room's agency to choose which moderation tools they utilize and that room's
ability to survive network partitions. This alternative does have an advantage of reducing bandwidth

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a Certificate-Transparency-like option?

A room admin MAY set a list L of policy servers, a count N, and a power level threshold T. By default, count is N=0, list L is empty, PL threshold is T=100. An even can only be incorporated if it originates from a user with PL≥T, OR it has N signatures from policy servers in L.

This way room admins can choose whom to trust, while avoiding a SPOF; they can also do an emergency override if it becomes necessary.

@mimi89999

This comment was marked as duplicate.

```

The request body is *optional* but *strongly recommended* for efficient processing, as the policy
server may not make efforts to locate the event over federation, especially during `/check`.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add «If the body is provided, the policy server SHALL verify that the event is signed by the claimed originating server.» to make the answer to the concerns in #4284 explicit?

spend across the federation (as there's no point in sending a spammy event if the policy server won't
sign it), but would require that communities upgrade their rooms to a compatible room version, which
typically take significant time to specify and deploy.

Copy link

@viccuad viccuad Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We’d especially like to see implementations for non-Synapse servers

I would like to suggest Kubewarden's policy-server. Kubewarden is a CNCF project implementing a policy engine for Kubernetes, and its policy-server can run outside k8s and process any type of query (disclaimer, I'm a maintainer of the Kubewarden project).

The policy-server runs small policies compiled to Wasm (written in Rust, Go, CEL, Rego, with our provided small SDKs). These policies are shipped as OCI wasm artifacts. The policy-server implements a Wasm host with wapc-rs, receives a JSON request and accepts, rejects, or mutates the request depending on the outcome from the policies. The policy-server also does context-aware calls to other services apart from the JSON request that is evaluating at that moment (in this specific case, that would be adding querying a Matrix client). Policy definitions allow for specifying granular permissions WRT those context-aware needs, ala smartphone apps.

Users of the policy-server can develop their own policies in their preferred languages, test them locally with our kwctl CLI tool, and share and reuse them via OCI registries.

If interested, don't hesitate to have a look at our docs, ping me, or get in contact in our Slack channel.

@vindicatorr

This comment was marked as duplicate.

policy server ahead of sending their event(s). For example, `matrix.example.org` may have a user in
the room with permission to send redactions and `/check`s all events.

## Potential issues
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mimi89999 says:

What if a malicious server claims that they received abusive content from a specific user (and forges events that seem to be originating from that user) in order to get a user banned globally? Is there anything protecting against such a scenario or is it something that should be considered by policy servers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following the attack vector here. The server cannot forge events to appear as coming from another server without getting those events rejected completely, making them out of scope of the policy server.

If a malicious policy server does decide to auto-fail all events from a specific sender though, it can do so. The room can also elect to not use that policy server anymore. Policy servers should be cognisant of the impact they have when making decisions.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attack vector is: a malicious homeserver in the room asks the policy server about another homeserver's event, and includes the event content as an optimisation. The content is forged, however. The policy server only follows explicit SHALL and SHOULD of the spec, accepts the event content and does not properly check its authenticity. The policy server proceeds to give a signed response that the event should be redacted. The malicious homeserver posts the response to get other homeservers to throw out the event. The stretch goal is to have enough blocked events allegedely from the same user in a row that some other policy mechanism bans the user.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the question is whether the policy server should be compelled to check hashes, or if it should be left as an implementation detail. I'm leaning towards implementation detail, as a room can change policy servers if needed, and it could be considered a security vulnerability in the implementation.

Copy link
Contributor

@Gnuxie Gnuxie May 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is annoying because it means that basic policy servers written as bots need to ask their own homeserver for each event (ie via GET /_matrix/client/v3/rooms/{roomId}/event/{eventId}) they get asked about. But i haven't read the whole proposal yet so my bad if i'm missing something.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The remainder of the proposal addresses that concern.


**TODO**: This section.

## Security considerations
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Servers should not send policy server state events through the policy server, or at least not act on them. Especially if the senders are the same.

This is to prevent a malicious policy server from not allowing the room to escape, but we should still have a mechanism to prevent compromised accounts from adding/setting malicious servers if we can.

Risk level of these 2 concerns is TBD.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client-server Client-Server API kind:core MSC which is critical to the protocol's success needs-implementation This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP. proposal A matrix spec change proposal s2s Server-to-Server API (federation) safety
Projects
None yet
Development

Successfully merging this pull request may close these issues.