Security

This page describes the security controls in the running system, in enough detail to verify them. It does not use the word 'bank-grade', and it does not claim a certification Rostack does not hold.

Last updated 12 September 2026

Encryption in transit

Every connection to Rostack uses TLS, terminated by Google Cloud with certificates it manages and renews. Responses carry Strict-Transport-Security with a two-year lifetime, includeSubDomains and preload, so once a browser has visited, it refuses to send anything to rostack.app over plain HTTP.

Calls from Rostack to Roblox, Stripe and Google services are likewise TLS only.

Encryption at rest

All stored data lives in Cloud Firestore, which encrypts it at rest with AES-256 as a property of the platform. Credentials get a second, independent layer: they are encrypted with Cloud KMS before being written, so a copy of the database alone yields ciphertext, and decrypting it requires a separate permission that a database read does not confer.

KeyProtectsRotation
workspace-credentialsRoblox Open Cloud API keys and authenticator secretsAutomatic, every 90 days
payout-credentialsRoblox account cookies used for payoutsAutomatic, every 90 days

Rotation creates a new key version for new encryptions while older versions continue to decrypt what they encrypted, so nothing is re-encrypted in bulk and nothing becomes unreadable. The secrets Rostack itself runs on, such as its Roblox sign-in secret and its Stripe keys, live in Google Secret Manager, readable only by the website's own service identity, and are never in the code.

Why the website cannot read a payout credential

Roblox publishes no API for group payouts. The only way to move Robux is a Roblox account cookie, which is far more powerful than the key ranking uses: it acts as the whole account. Rostack handles that asymmetrically.

ComponentPermission on the payout key
The public websiteEncrypt only
svc-payout, an isolated serviceDecrypt only

The website can therefore store a credential it is permanently unable to read back. The service that can decrypt it accepts requests only from the website's own service identity: Google rejects every other caller, signed in or not, before a request reaches it. It has two software dependencies in total. The plaintext exists inside one request and is never logged or written anywhere.

Nor does it take the website's word for what to pay. The website asks it to pay one run, under a release it has just started, and the service reads that run from the database for itself, with read-only access. It pays only a run recorded as being released under that exact release, started in the last five minutes and approved by a second person when its size needs one, and only the recipients and amounts recorded on it. It refuses any run above ceilings set on the service itself, which nothing in the database can raise: 1,000,000 Robux in one run and 100,000 to one person. Anything else is refused before the credential is opened.

What this does and does not defend

A compromised website gets ciphertext it cannot open, and a request to the payout service can only pay a run the database records as approved and being released, exactly as recorded. What the service cannot tell apart is a run forged in the database by someone holding the website's own identity, which can write there; the ceilings limit what one such run could send. It does not defend against the person who owns the Roblox account handing their cookie to someone else, and it cannot reverse a Robux payout once Roblox has processed it. The payout screen says so before a credential is connected.

Ranking does not use your account cookie

Ranking runs on Roblox's official OAuth for sign-in and on the Open Cloud API for changing roles, authenticated by an API key you create in Roblox's own dashboard with exactly the scopes it needs. Rostack never asks for a cookie to rank anyone.

Rostack's own API keys, the ones your game server or bot presents, are stored only as a SHA-256 hash. The plaintext is shown once at creation. A copy of the database contains nothing that can call the ranking API.

Authentication for money

Using payouts at all requires a verified email address and an authenticator app enrolled on the account. Everything that moves money, or decides in advance that it will, asks for a fresh code at that moment: connecting a payout credential, releasing a run, approving one as the second person, and setting up, changing, approving, pausing, resuming or deleting a payout schedule.

Codes are checked at the moment of the action rather than at sign-in, because a session lasts fourteen days and "they used a second factor a fortnight ago" is a much weaker statement than "they are holding the phone now". Each code works once: the matched time step is recorded in the same database transaction that checks it, and anything at or before it is refused. A code observed over someone's shoulder cannot release a second payout inside its thirty-second window, and two requests racing with one code cannot both pass.

After five wrong codes in a row, the account has to wait fifteen minutes before another code is even checked, and each further wrong code doubles the wait, up to a day at a time. At that pace, guessing a six-digit code would take centuries on average. The wait is shown in Settings, next to a button that signs the account out everywhere, which ends whatever session the guesses came from.

Removing the authenticator also requires a current code, so a hijacked session cannot strip the second factor and then move money. Adding one requires a sign-in from the last ten minutes, so a hijacked session on an account without one cannot add its own either.

A payout schedule is the one place money moves with nobody present, so its consent is given in advance and is specific. Each approval, given with a code, names one version of the terms, and any change to who, how much or when voids it. At or above the second-approval threshold, somebody other than the person who set it up has to approve. The approved terms are sealed with Cloud KMS, and a schedule whose stored terms stop matching the seal pauses instead of paying. Each time it fires, Rostack checks again that everyone behind it still holds their permission at their live Roblox rank, asking Roblox rather than trusting a stored rank, and that each approver still has the authenticator they approved with. If Roblox cannot answer, it waits for the next check, and after about an hour it drafts the run or pauses the schedule rather than guess. If anything has changed, it drafts the run for a person to release. Even when its timing is changed, a monthly or weekly schedule pays at most once per calendar month or week, and a biweekly one at least thirteen days after its last payment. Pausing, changing or deleting a schedule stops a payment it has not sent yet.

Paying for Rostack

Plans are bought on Stripe's own checkout page and managed in Stripe's customer portal, so card details are typed into Stripe and never reach Rostack's servers. Only a workspace's owner can start a checkout or open the portal for it.

A plan changes only when Stripe's webhook says a payment happened, and every delivery is checked against Stripe's signature before it is believed. Coming back from checkout grants nothing on its own. Each event is answered by reading the subscription fresh from Stripe, so a delivery that arrives late, twice or out of order cannot leave a workspace on the wrong plan. Plan payments and Robux payouts run on separate systems with separate credentials, and never meet.

Authorization

Two authorities apply to every action and they are not the same thing. Your Roblox rank is the ceiling: a Rostack seat can hold less authority than its group rank allows, never more. Rostack permissions are the grant within that ceiling. A compromised Rostack account is therefore strictly less dangerous than the Roblox account behind it, and demoting someone in Roblox demotes them here.

Because Roblox sends no notifications when ranks change, actions that change state re-read the live rank from Roblox before acting. Nobody can edit their own access, grant a permission they do not hold, or act on a seat at or above their own rank.

The audit log

Every privileged action is written to the log before the action runs, with the actor, the reason and a trace ID, then updated with the outcome. A crash mid-action still leaves evidence that it was attempted. The log is append-only in Firestore's security rules, so no client, including ours, can edit or delete an entry through the application.

Browser-side protections

Pages are served with a Content Security Policy that forbids inline scripts unless they carry a per-response nonce, forbids framing entirely, restricts form submission to Rostack's own origin, and limits network requests to Rostack and the Google authentication endpoints. No payment script runs on rostack.app. Sessions are an httpOnly, Secure, SameSite=Lax cookie that JavaScript cannot read.

Your data

From Settings you can download everything Rostack holds about you as a JSON file, or delete your account. Both are immediate and self-service. Deleting your account ends every session, removes your sign-in, authenticator, seats and warnings, and revokes pending invitations. What is retained afterwards, and why, is listed on the privacy page and shown to you before you confirm.

What is not claimed

Rostack has not undergone a SOC 2 or ISO 27001 audit and has not commissioned an independent penetration test. This page will say so until that changes. If you find a vulnerability, please report it privately to security@rostack.app rather than publicly.