These scripts hold a Synapse server-admin token. A bad command is visible homeserver-wide and a few are not reversible. Read this once before running anything new.
Before any state-changing command:
- Confirm the homeserver URL in
~/.config/matrix/config.json— the wrong host with the right script wipes the wrong server. - Confirm the user/room/space ID you typed. Matrix IDs are similar; copy/paste them and read them back.
- Run any read-only script first to verify the target exists:
python3 …/synapse-user-rooms.py '@user:server'python3 …/synapse-room-member-flow.py '!room:server'
- For destructive operations, dry-run by hand: print the planned action to stdout (
echo,python3 -c 'print(…)') and ask the operator to confirm before invoking the script.
- Calls
POST /_synapse/admin/v1/deactivate/{user_id}. - The user cannot log in again, all access tokens are revoked, the user is left from every joined room.
- With
--erase, message bodies are also redacted (GDPR right-to-erasure). - Not reversible without a database operation by a homeserver operator.
- The script prints the user's profile + joined rooms before and after, and refuses to run non-interactively without
--yes.
The hardening pipeline is partially irreversible:
| Step | Reversible? |
|---|---|
| Add to space | yes — remove the m.space.child event |
| Force-join the caller | yes — leave the room |
| Promote to PL 100 | yes — restored at the end of the pipeline |
Switch public → restricted |
yes — change m.room.join_rules back |
| Enable encryption | no — Megolm cannot be turned off |
The room version must be > 9 for restricted joins; otherwise the script prints a red ❌ for that step. Switching to restricted removes discoverability for users not in the parent space.
Like synapse-deactivate-user.py, the script reads the room's current state, prints the steps it would take — marking the encryption step as one that cannot be undone — and then asks. --yes skips the question and is required without a terminal. The question comes before the first write, so aborting leaves the room untouched.
- Only works while some existing admin is still in the room (Synapse refuses otherwise).
- If the original owner has already left, the room is unrecoverable through this tool — Synapse explicitly forbids re-creating admin from outside.
- Read-only on the API. Risk is misinterpretation: only unencrypted messages are indexed. An empty result on an E2EE room means "search saw nothing", not "the user did not say anything". Use Element / a real client when you need plaintext from an encrypted room.
- Read-only, but the resulting
rooms.jsoncontains user IDs, room names, power levels and join policies for every indexed room. - Never commit it — the skill's
.gitignoredoes not cover the working directory the script is run in. - Treat the file the same as the admin token.
- The admin token is equivalent to root on the homeserver. Store it only in
~/.config/matrix/config.json(or a secret manager that writes that file at startup). - Rotate it after onboarding/offboarding any user who had file-system access to a host that ran these scripts.
- If you publish a Docker image (e.g. the graph dashboard from
room-graph-pipeline.md), pass the token via--secret, never viaENVor build args.