Skip to content

How security works

Who can use SiteRelay, how two sites prove who they are, how secrets are stored, and what SiteRelay refuses to run.

ReferenceFor SiteRelay 1.0.04 min read

SiteRelay moves whole sites, including databases with user accounts. So it's built to let in only the people and sites you've chosen, to run only what it wrote itself, and to always keep a way back.

Who can use SiteRelay

  • SiteRelay's screens and its REST API (/wp-json/relay/v1/…) need an administrator: the manage_options capability, or manage_network_options on a network. The relay_capability filter can change it.
  • Every request from the screens carries WordPress' REST nonce, so another site can't make your browser act on SiteRelay (no cross-site request forgery).
  • Downloads of exports and backups go through that same check. A link works only for a logged-in administrator.

How two sites trust each other

Two sites running SiteRelay talk directly to each other. No server in between sees your data.

Access keys. A site lets another in only with one of its access keys, and only as far as its site mode allows. Both are checked on every request. See Site modes and access keys.

Signed requests. Every request is signed with the key's secret, which never travels after the connection string is pasted:

  • The signature is an HMAC-SHA256 over the operation, the job, the key id, a timestamp, a random nonce and a SHA-256 hash of the body.
  • The receiving site refuses a request whose signature doesn't match, whose timestamp is more than 5 minutes off, or whose nonce it has already seen in the last 15 minutes. So a captured request can't be replayed.
  • The signature is checked by WordPress' own permission check on the route (/wp-json/relay/v1/remote), before any of SiteRelay's code for the request runs.
  • Answers are signed too, tied to the request's nonce. A site in the middle can't feed back answers of its own.

Encryption in transit. SiteRelay signs everything it sends, but the content travels as the connection carries it. Use https:// between real sites, and the data is encrypted on the way. Allow insecure connection (plain http:// or a self-signed certificate) exists for local test sites.

HTTP basic auth. If a site sits behind a username and password, SiteRelay can send them with every request.

Secrets at rest

These are stored encrypted with libsodium's secretbox:

  • access keys' secrets;
  • saved connections' secrets and basic-auth passwords.

The encryption key comes from the site's AUTH_KEY and AUTH_SALT. If you change those salts, the stored secrets can't be read any more. Create new access keys and reconnect.

SiteRelay never shows a secret again after creating it. The Help screen's diagnostics contain no passwords or keys.

What SiteRelay accepts as SQL

A migration or a backup carries SQL into your database, so SiteRelay checks every statement before it runs.

From another site or a backup (pull, push, restore): only the statements SiteRelay's own writer produces are accepted:

  • CREATE TABLE, for the InnoDB, MyISAM, Aria and MEMORY engines;
  • INSERT with plain literal values.

Every table name is rewritten to a temporary import table. Anything else is refused before it reaches the database, and the job stops with a message saying the other site (or the backup) sent a statement SiteRelay won't run.

From an imported dump (mysqldump, phpMyAdmin or SiteRelay's own export), a wider but still fixed set runs, and only against SiteRelay's import tables, never the live ones:

  • CREATE TABLE (without foreign keys);
  • INSERT or REPLACE with plain values;
  • DROP TABLE;
  • ALTER TABLE that adds keys, changes columns or sets AUTO_INCREMENT.

Only the WordPress site's own tables (its table prefix) are touched. Session settings, locks, transactions, views, triggers, stored routines, other applications' tables and anything unrecognised are skipped and counted, never run. A data statement for a WordPress table that isn't plain is refused.

The new tables replace the live ones only at the end, in one step.

Files from elsewhere

  • Every path in a file list from another site, or inside a backup, must be a plain path that stays inside its folder (themes, plugins, must-use plugins, uploads or other wp-content). Anything with .., odd characters or an absolute path is refused.
  • SiteRelay's own plugin, its must-use plugin and its private folders can't be overwritten by a migration or a backup.
  • A backup .zip whose files would inflate far beyond their packed size (a "zip bomb") is rejected rather than filling memory.

Private storage

Exports and backups live in wp-content/uploads/relay. The folder has an index.php and a deny-all .htaccess, and the backup files have unguessable names. SiteRelay's working folders (wp-content/relay-staging, wp-content/relay-backups) are protected the same way.

A way back

Not strictly security, but it's what makes mistakes recoverable:

  • Every pull, push, import, restore and find & replace saves a restore point first. See Undo anything.
  • After a pull, push, import or backup restore, SiteRelay loads the site. If it no longer loads, SiteRelay switches everything back and says why.

What leaves your site

Where What When
The other site What you chose to pull or push Only during a pull or push you started, or one it started with your key
Your email or webhook A one-line summary of the job, and its details (webhook) Only with Notifications switched on

Nothing else, and never to a third party.

Stuck? Troubleshooting explains every message SiteRelay shows, and what to send when you ask for help.