Security
Every request through one door.
The platform exists to put a door in front of small software. This page says what that door does, what is behind it, and how to tell us if you find a way around it.
The edge is the only way in
An app deployed on Jiayang Cloud has no address of its own. JavaScript apps run in a dispatch namespace with no routes; container apps have no public ingress. The only path to either is the edge Worker, which handles every request for every app before the app sees it.
The edge resolves the caller's session or bearer token, refuses cross-site writes, evaluates the workspace's access rules, and only then forwards the request. A request that fails any step is denied and logged. There is no bypass for us, either: platform components reach apps the same way.
Identity is signed, never assumed
For each request it allows, the edge mints a fresh identity token and passes it to the app in the X-Jiayang-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. The SDKs verify the signature against the platform's published key set, plus the issuer, the audience and the expiry, before telling your code who is calling.
Before the edge sets that header it deletes every inbound header that could carry an identity, including any X-Jiayang-* header a client sent. So the presence of a header proves nothing, and nothing a client can send is mistaken for the platform. The edge sets exactly two headers about the caller: X-Jiayang-Identity, the signed token, and X-Jiayang-Email, a convenience for display that the SDKs never rely on.
Fail closed
Missing configuration, an unreachable key set, a failed access-rule lookup, a database error: each of these ends in a denial, never a default allow. Access is denied unless a rule explicitly 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 or revoking a bearer token 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. Revoking a browser session, from the account menu, ends it in the dashboard at once and in every app within 60 seconds. Bearer tokens are stored as hashes and can be revoked one at a time.
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. The test suite that runs on every change to the platform includes tests that tenant A cannot reach tenant B's database, storage, secrets or logs, for both runtimes.
An app's outgoing traffic goes through an egress proxy that refuses connections to the platform's own hosts, so an app cannot reach the control plane, the edge or another app from the inside.
Apps hold no secrets
Third-party credentials your app needs live in the control plane, encrypted with a platform key, and are attached to the app's outgoing requests by the egress proxy 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, and they are not attached at all while the workspace is suspended or once it is deleted. 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. Environment values are encrypted the same way. Platform secrets are held in the providers' secret stores and never in source code or CI logs.
Encryption
All traffic is TLS. Data at rest is encrypted by the providers that store it (Cloudflare and Neon). Secrets get the additional layer above. Session cookies are __Host- prefixed, signed, host-only, and verified on every request; sign-in codes and tokens are stored hashed.
Everything is logged
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. Workspace members can watch it live, and the owner can export it on every plan. Retention is 3 months on Free and Team and 12 months on Business, after which entries are deleted; after a downgrade, entries older than the new plan's retention are deleted 30 days after the plan changed.
How we work
- Every change passes an automated suite before it is deployed, including an adversarial authentication test set: no token, malformed tokens,
alg: none, algorithm confusion, wrong key, wrong issuer or audience, expired and not-yet-valid tokens, replayed tokens, client-supplied identity headers, revoked grants and tokens, direct invocation of an app outside the edge, and key rotation and key-set outages mid-request. A change to authentication adds a case. - Every change is deployed to staging, and its checks pass there, before it is deployed to production. The one exception is a revert while staging itself is broken, which can go to production without the staging check; that is done by hand, one deployment at a time, and the deployment's record shows the check was skipped.
- Staff access to production is limited to what operating the service needs, goes through the providers' own access controls, and is logged.
- The SDKs are open source, under the Apache License 2.0, at github.com/ss2d22/jiayang, so you can read exactly what your app trusts. The CLI is not open source: it is released there as binaries only, each with its SHA-256 checksum beside it.
What is yours to do
- Verify the identity token. The SDKs do it in one call; if you don't use them, verify the signature,
iss,audandexpyourself, and never trust a header alone. - Treat bearer tokens as secrets. Create one per script, name it, and revoke it when the script is retired.
- A public path is open to the internet. The edge rate-limits anonymous requests to it per client and never counts them against the workspace's request allowance. A path can require a provider's signature, which the platform checks before the app sees the request, with a secret that never reaches the app. On a public path that doesn't require one, the app must check a sender's signature itself.
- Keep control of the mailbox you sign in with; it is your account.
Reporting a vulnerability
If you find a security problem in the platform, the SDKs, the CLI or this website, email security@jiayang.cloud. 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:
- test against your own workspaces and apps, never someone else's;
- stop as soon as you have enough to show the problem, and don't access, change or delete data that isn't yours;
- don't run denial-of-service tests, spam, or social engineering against our staff or customers;
- give us a reasonable time to fix the problem before you publish it.
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.