01Platform tokens are encrypted at rest
The credentials for every connected account — OAuth tokens, bot tokens, app passwords, webhook URLs — are encrypted with AES-256-GCM before they are stored, and decrypted in exactly one place, at the moment a delivery needs them.
A copy of the database on its own cannot post as anyone. Secret fields a platform asks for at connection time are never returned by the API after they are saved.
02API keys are stored only as hashes
A key is shown once, when it is created. What is kept is a hash of it, which can check a key but cannot be turned back into one — so a key that is lost is revoked and replaced, never recovered.
- Keys carry scopes: a key that only reads cannot publish or connect
- Keys are listed and revoked in the console or over the API
03People sign in with their Rutba account
The Relay console has no password of its own. People sign in through Rutba’s single sign-in, with two-step verification, and arrive in the console holding a session there. An organisation’s roles decide what each person can do.
04Every organisation is kept apart
Every read and write is scoped to the organisation making it. A request for another organisation’s post, connection or key is answered as not found — not as forbidden, because confirming that something exists is itself a leak. The test suite asserts this for every resource and every kind of credential.
05An audit trail, for people and for keys
Every action that touches a credential writes an audit entry, whether a person took it in the console or an integration took it with an API key. A trail that recorded only people would go quiet exactly when an automated integration did something unexpected.
06Rate limits, and pacing towards platforms
Requests are rate limited per key, and the public catalogue per address, with the limits returned in response headers. Towards the platforms, publishing to each account is paced below that platform’s documented ceiling: some networks treat a burst as spam and act on the account, which costs far more than a post arriving a minute later.
07Kill switches, from narrow to wide
When a platform misbehaves, publishing can be paused for that platform, for one organisation, or for a single connection, without a deploy. A paused delivery is deferred and picked up again when the pause lifts — never failed, because failing it would lose the post as well as the incident.
A pause can be given an expiry, so a switch nobody remembers to turn off does not become an outage of its own.
08Media fetched safely, and checked by content
When a post gives a media URL, the address is resolved before any connection opens and refused if it points anywhere private — loopback, private ranges, link-local and cloud metadata addresses. Redirects are followed one hop at a time, and every hop is checked.
Uploads are identified by the bytes at the start of the file, against an allow-list, never by their extension or the type the client claims.
09Signed webhooks that cannot be replayed
Every webhook carries v1 = HMAC-SHA256(secret, "{timestamp}.{body}"). The timestamp is inside what is signed, so a captured request cannot be sent again later with a new time, and a receiver can refuse anything outside a few minutes. Secrets can be rotated per endpoint.
10Connections made carefully
The OAuth state that ties a platform’s sign-in back to your organisation is created by the relay, used once, and expires in minutes. Hosted connect links expire once used or after a short time. A connection that stops working is flagged once and the organisation is told, rather than every queued post rediscovering it.
Your data, on your terms
Disconnecting an account removes its stored credentials. The data deletion page explains how to revoke access from a platform’s side too, or close an organisation entirely. To report a security concern, write to support@rutba.io.
This page describes controls in the product’s code. It is not a certification or an audit report, and it is not presented as one.