Security

How we keep your apps private

Every app on Forculus sits behind our edge. This page says what the edge checks, how apps and workspaces are kept apart, and how to report a problem.

Last updated 21 October 2026

The edge is the only way in

An app deployed on Forculus has no address of its own. JavaScript apps run in a dispatch namespace with no routes, and container apps have no public ingress. The only way to reach either is the edge Worker, which handles every request for every app before the app sees it.

The edge works out who the caller is from their session or bearer token, refuses cross-site writes, and checks the workspace's access rules. Only then does it forward the request. A request that fails any step is denied and logged. Our own components also reach apps only through the edge.

Signed identity

For each request it allows, the edge creates a fresh identity token and passes it to the app in the X-Forculus-Identity header. The token is a JWT signed with the platform's private key, valid for 60 seconds and bound to the app it is for. Before telling your code who is calling, the SDKs check the signature against the platform's published key set, and check the issuer, the audience and the expiry.

Before the edge sets that header it deletes every inbound header that could carry an identity, including any X-Forculus-* header a client sent. A header a client sends can't pass for one the platform set. The edge sets exactly two headers about the caller: X-Forculus-Identity, the signed token, and X-Forculus-Email, a convenience for display that the SDKs never rely on.

Failing closed

If configuration is missing, an access-rule lookup fails or the database returns an error, the request is denied. If an SDK can't reach the key set, it refuses the identity token. Access is denied unless a rule allows it. Every platform Worker checks its own configuration on every request and refuses to serve when a value is missing.

Revocation within a minute

Removing someone from an app takes effect within 60 seconds, including for connections that are already open. The edge watches long-lived responses and closes them when the grant behind them goes away. A revoked bypass token is refused on its next request, and connections already open with it close within 15 seconds. Revoking a browser session, from the account menu, ends it in the dashboard at once and in every app within 60 seconds. Tokens are stored as hashes, and each can be revoked on its own.

Workspaces are kept apart

Every table in the control-plane database that holds workspace data carries a row-level security policy, enforced by Postgres itself, so a query can never return another workspace's rows, whatever the application code does. Each app runs in its own isolate or container with its own storage, its own secrets and its own logs. Every change to the platform runs tests on a full copy of it. They deploy apps for two workspaces side by side, on both runtimes: JavaScript apps, and container apps in real containers. They check that neither workspace's apps can read the other's database, files, secrets or logs.

An app's outgoing traffic goes through an egress proxy that refuses connections to the platform's own hosts and to private addresses, so an app cannot reach the control plane, the edge or another app from the inside. The one exception is the public key set at edge.forculuslabs.tech that apps verify tokens with.

Apps hold no secrets

Third-party credentials your app needs live in the control plane, encrypted with a platform key. The egress proxy attaches them to the app's outgoing requests at the moment of the request. They are never shown back to a person after being set, and never appear in the app's code, its environment listing or its logs. They are not attached at all while the workspace is suspended or once it is deleted. While an app isn't being served, the egress proxy refuses every request it makes. A webhook provider's signing secret, set on a public path, is kept the same way, but the control plane decrypts it to check every delivery sent to its path, and the app gets the platform's signed webhook token instead of the secret. A Postgres database you connect is kept the same way: its password is encrypted in the control plane and given only to Cloudflare Hyperdrive, which holds the connection to it. Apps send their SQL through the egress proxy, which lets through only the databases an app was given, and never see the password. The address must be one the internet can reach: private and internal addresses are refused. Environment variables are not secrets. Their values are stored as you set them, and anyone who can edit the app can read them. Platform secrets are held in the providers' secret stores and never in source code or CI logs.

Every deploy is scanned

Before a version goes live we look for keys and tokens left in what it deploys, and check the packages its lock files pin against OSV (osv.dev), the open vulnerability database. Only package names and versions go to OSV, and never a private package’s. Private keys and live tokens are always refused. For everything else a workspace chooses whether a finding warns or refuses the deploy, and each scan is kept with its version and in the audit log. How scans work.

Encryption

All traffic is TLS. Data at rest is encrypted by the providers that store it, Cloudflare and Neon. Secrets get the extra layer described above. Session cookies are __Host- prefixed, signed, host-only, and verified on every request. Sign-in codes and tokens are stored hashed. A passkey must verify the person, with a fingerprint, face or PIN, and works only on the dashboard's own address.

Audit log

Every request to every app and every administrative action is written to an append-only audit log with who did it, when and from where. The workspace's owners and admins can read it and follow it live, and the owner can export it on every plan. Retention is 3 months on Free and Team and 12 months on Business and Enterprise, after which entries are deleted within two days. After any change of plan, entries older than the new plan's retention are deleted 30 days after the plan changed. Most entries older than 30 days are kept in Cloudflare R2, which Cloudflare is asked to keep in the Asia-Pacific region, encrypted with a key that belongs to the workspace.

Where data is kept

The control plane’s database is in AWS ap-southeast-1 (Singapore). Apps’ databases, files and containers are kept and run by Cloudflare, in the Cloudflare region nearest where the person who created the app was. The archived audit log is in Cloudflare R2, which Cloudflare is asked to keep in the Asia-Pacific region. Requests are served from Cloudflare’s network around the world.

Keeping an Enterprise workspace's data in the EU isn't open yet. Write to sales@forculuslabs.tech to hear when it is. The docs say what it will cover and what it won't.

Backups and recovery

Each kind of data has its own way back, and these are the recovery point (RPO: the newest state a restore can bring back) and the recovery time (RTO: how soon it is back) for each.

The docs say how to restore each.

How we work

Your part

Reporting a vulnerability

If you find a security problem in the platform, the SDKs, the CLI or this website, email security@forculuslabs.tech. Include what you found, how to reproduce it, and what you think the impact is. We acknowledge reports within two business days, keep you informed while we fix the problem, and credit you when it is fixed if you would like that.

We ask that you:

If you follow those rules we won't take legal action against you for the research, and we consider it authorised under our terms. We don't currently run a paid bounty programme. Problems in a customer's own app belong to that customer. If you can't reach them, tell us and we will pass it on.

Reporting abuse

To report phishing, malware, spam or other abuse on an app hosted on forculuslabs-apps.tech, email abuse@forculuslabs.tech. Include the app's address, what you saw and when. We reply within two business days, and we take down an app that is being used for abuse.

Report child sexual abuse material to the same address. Send the app's address, never the material itself. We take it down and report it to the Singapore Police Force and to the National Center for Missing & Exploited Children (NCMEC).

Send copyright complaints to legal@forculuslabs.tech, the address we have set up to receive takedown notices under Singapore's Copyright Act 2021. The terms say what a notice must include and what we do with it.