# somewhere.tech — Security Practices > Part of the somewhere.tech documentation. For the complete platform reference, see [/llms.txt](https://somewhere.tech/llms.txt). Call-level API + every tool: [/docs.txt](https://somewhere.tech/docs.txt). This document describes how somewhere.tech protects your application, your data, and your end-users' data. It is written for technical scrutiny — paste it into an AI and ask "is this good enough for what I'm building?" Everything below is a capability you can verify. Last reviewed: 2026-07-14. --- ## 1. The authority model Every request to the platform API (`/v1/*`) resolves to exactly one **authority**. This is the spine of the security model — what you can do depends entirely on which credential you present. | Authority | Who it is | What it can do | |---|---|---| | **anonymous** | No credential | Static files, public webhooks (signature-verified), the pre-login auth flows | | **app_user** | An end-user of *your* app (per-project JWT) | Use app-user data routes for one project. Direct database access (structured, raw, or batch) is constrained by the table-intent rules in §3; no project configuration or schema changes. | | **runtime_project** | Your deployed server functions (`sw.*`) | Application primitives (database, files, email, AI, …) for **one project**. Cannot touch platform configuration (deploy, environment variables, keys, billing, domains). | | **internal_signed** | Platform delivery (jobs, scheduled tasks, webhooks) | HMAC-signed, timestamped platform-internal delivery only. | | **developer_admin** | You (the project owner, via `smt_` key or dashboard) | Full control of **your** projects. Audit-logged. | A credential of one kind cannot act as another. A runtime key cannot mint developer actions; an app_user JWT cannot run admin operations. Each `/v1/*` route declares which authorities it accepts and the capability required, and that policy is verified continuously (see §8). **The "two-door" principle:** admin/config routes (deploy, environment variables, keys, domains, billing) are developer-only and never reachable by app_users or runtime keys. Direct app-user database requests pass through the table-intent boundary in §3. Calls made by your deployed server functions use project-level authority, so authorization inside those functions remains your responsibility. --- ## 2. Data isolation - **Each project gets its own database.** Projects do not share a database; there is no cross-project query path. A query in project A physically cannot read project B's data. - **Runtime keys are project-bound.** A deployed function's key carries its `project_id` and a capability set; it cannot spoof another project via body, query, or path. Cross-project access returns "not found." - **Tenant compute isolation.** Each project's server code runs in isolated per-request execution on the platform runtime. Customer apps do not share memory, file state, or execution state. - **Files are private by default.** Uploaded files are not publicly readable by path-guessing; a visibility check gates every serve. You opt a file into public serving explicitly. --- ## 3. Database access: server functions and declared table intent Somewhere provides backend-enforced app-user identity, project isolation, managed account-ban controls, and a fail-closed table-intent boundary inside server functions. You declare each application table as user-scoped, shared, or server-only (`server_only` on the wire). That choice — not the presence of a `user_id` or `owner_id` column — determines whether per-user ownership is enforced. Browser code cannot submit raw SQL. For ordinary declared browser operations, client grants in `db/schema.ts` generate the typed `somewhere:data` client and the platform enforces the declared identity, operation, and columns. Generic browser database routes are refused with `BROWSER_DB_ACCESS_REMOVED`; custom business logic calls deployed server functions. Inside those functions, per-user scoping runs through the structured query builder (`sw.db.from` / `count` / `insert` / `update` / `remove`), which the platform scopes to the signed-in user. On managed projects, ordinary `sw.db.query` and `sw.db.batch` calls are refused before reaching the database. A function can deliberately bypass declared row permissions for a raw read through `sw.db.server.query` or `sw.db.server.batch`, after it authorizes the caller itself. The platform does not rewrite that SQL or infer who may see its result. Before a structured query runs, its table must have a recognized intent. Undeclared tables and unknown declarations are rejected on that path. | Table intent | Declared structured behavior | |---|---| | **user-scoped** | For ordinary app users, reads, updates, and deletes are restricted to rows owned by the caller; inserts and upserts force the owner field server-side. Structured queries apply this automatically. Explicit `sw.db.server.*` operations bypass per-row ownership and require application authorization. | | **shared** | App users can read and write rows across users by design. Use this only for intentionally shared application data. | | **server-only** (`server_only`) | User-context access is rejected. Platform-managed tables such as `auth_users`, plus reserved internal tables, remain unavailable to app users regardless of project declarations. | Automatic row ownership applies only to tables you declare user-scoped. Shared tables are not auto-scoped. Browser sessions cannot submit SQL. Database migration, dump, export, and restore operations remain developer-only. These controls apply when a server function uses the structured query builder for a signed-in app user. The explicit `sw.db.server` namespace and developer credentials carry broader project authority. Application authorization, what server handlers return to callers, and intentional shared or administrative behavior remain the developer's responsibility. --- ## 4. Authentication & transport - **TLS everywhere.** All traffic to the platform API and deployed apps uses HTTPS. There is no unencrypted path to either surface. - **Passwords** (for end-user accounts in your app, and for developer accounts) are hashed with **bcrypt**, with a unique per-password salt. Plaintext passwords are never stored and never logged. - **Tokens are signed, not guessable.** App_user sessions are JWTs signed with a **per-project secret** — a token from one project is invalid for another. Developer dashboard sessions live in **HttpOnly cookies** (not readable by JavaScript, so XSS in the dashboard can't exfiltrate the session). API access uses `smt_` developer keys (hashed at rest — we store only the SHA-256 of the key, never the key itself). - **MFA** (TOTP) is available for end-user accounts, and it is challenged on PASSWORD sign-in. Magic link, OAuth and passkey sign-in are not challenged for the second factor, so on an account that has one of those enabled, MFA does not by itself make password the only way in. --- ## 5. The security review On paid plans an AI security reviewer reads your server functions and flags common issues. It runs automatically when you promote a preview and in a daily pass over recently deployed projects, and on demand after any deploy (the security review call). It is a bounded review of server functions, not a whole-app certification: incomplete input can never establish a clean review — a partial review may still report risks it found, but a partial review with nothing found is reported as indeterminate, not as clean. It flags: - unscoped database queries (missing ownership predicates), - routes that should require auth but don't, - secrets committed into client-visible code, (this source review cannot see every value set later through project environment settings; a public `VITE_*` or `REACT_APP_*` value is compiled into browser code, and known server credentials are refused there), - unsafe external fetches. Outbound requests from deployed functions are policed at run time: preview functions cannot make outbound requests; the runtime refuses a destination in a private, loopback, link-local or cloud-metadata range, as written or as resolved, and re-checks each redirect it follows; and, behind the runtime, the platform's outbound guard refuses a request that reaches it with a literal blocked target — a non-public address or internal hostname, embedded credentials, a non-HTTP scheme, or a port other than 80, 443 or 1024 and above — with a 403 before it leaves. The guard classifies the URL as written and does not resolve names. The review depth scales with plan (a stronger model on higher tiers). **Where findings appear.** The dashboard's Security page and `GET /v1/security/findings` (developer key) list the open findings across the projects you own and the projects shared with you as a collaborator or group member. Each finding names its source — a browser-visible secret, a server file served as public static source, a mass-assignment write, or the model review — one of four severities (critical, high, medium, low), a workflow status (open, fix in progress, needs verification, accepted risk), and the file and line. A resolved finding drops off the list; an accepted-risk finding stays visible. Where a finding exists both in the current findings record and in an older copy from before that record existed, only the current one is listed; findings from different sources are separate findings and are not merged. The list is the findings themselves; each review run's own record is described next, and cross-project attention ranking is not part of this contract. **Review history and detail.** Every review run is kept as its own record. The dashboard's Security page lists a project's runs, newest first, and opens one run directly at `/dashboard/security?project=&run=`. The same records are available to your developer key at `GET /v1/security/reviews?project_id=` (newest first, `limit` 1–50, and a `cursor` for the next page) and `GET /v1/security/reviews/?project_id=`. Anyone with access to the project — the owner, a direct collaborator, or a group member — can read them; there is no separate role. A run names what triggered it (a deploy, a manual request, or the scheduled pass), the version it reviewed, when it started and finished, its outcome, its coverage (files checked out of files total, and whether coverage was complete), the finding count, and a `detail_state` saying whether its exact detail is available. The exact detail, when available, carries one of three statuses: `clear`, `risks_found`, or `indeterminate`. The review covers deployed server functions only. A failed run is `indeterminate` even when the model's own answer was clear, and keeps the validated findings it did produce, with the failure stated first. Incomplete input cannot establish `clear`; a review of incomplete input may still report `risks_found`. History is exact: asking for a run returns that run, never the latest successful one in its place, and a run whose stored detail is unfinished, missing, not stored, temporarily unavailable, or unreadable says so in its `detail_state` instead of being substituted. The findings text is rendered from the validated result, never raw model output. When a run's exact detail is successfully saved, the project owner — not collaborators — receives an in-product notification on the dashboard linking to that run, marked high priority only when validated findings justify it. Skipped, ineligible, and unfinished runs, and runs whose detail could not be saved, send no notification. Runs from before this notification existed are not back-filled. The review is advisory: its findings never block or undo a deploy. Every deploy also runs a deterministic scanner for the highest-confidence patterns; its findings are warnings and never block the deploy either. --- ## 6. Infrastructure somewhere.tech runs on a globally distributed platform designed for secure, isolated application execution. - **Compute:** your code runs in isolated per-request execution, with no long-lived servers for you to patch and no shared execution state between projects. - **Database:** a managed SQL database, one per project, isolated from every other tenant. - **Files:** managed file storage with **zero egress fees**, so we have no incentive to meter or throttle your traffic. - **Backups & recovery:** database dumps and table exports provide portable recovery copies. Migration bookmarks record operational recovery markers; managed in-place restore is unavailable. - **Edge protection:** network-level DDoS mitigation and a web application firewall sit in front of every request, including your deployed apps. --- ## 7. Rate limiting & abuse controls - **Per-endpoint, app-defined:** your functions can rate-limit any operation via `sw.rateLimit` (atomic, per-key counters). - **Per-plan API limits** protect the platform and your project from runaway traffic. - **AI spend** is gated by a prepaid balance plus a per-plan soft-cap warning, so a runaway loop can't silently run up an unbounded bill. --- ## 8. The security program Security here is a standing program, not a one-time audit: - **A live security matrix** runs on every deploy: it probes every sensitive route with each authority (anonymous, app_user, runtime, developer, internal) and asserts the exact response at runtime — proving the wrong caller is rejected, not just that the route declares the right policy. A route that starts admitting the wrong principal fails this gate. - **Runtime isolation.** A deployed function's key can reach only the application primitives for its own project; the entire platform-configuration surface — deploy, environment variables, keys, domains, billing — is closed to runtime keys and verified by the matrix above. - **Regression-tested fixes.** Every issue we find gets a permanent regression test, so the same class of problem cannot recur silently. --- ## 9. Security research & reporting Good-faith security research is welcome and authorized when it follows this policy. You may test Somewhere-operated websites and APIs using accounts and projects you control, or whose owners have explicitly authorized your testing. Use synthetic data. You may test isolation between your own test accounts and projects; no advance approval is needed for testing within these boundaries. This permission does not cover other customers' accounts, applications or data, or the systems of our infrastructure providers and other third parties. Do not perform denial-of-service or load testing, social engineering, credential theft, or actions that disrupt the service or damage data outside your own disposable test projects. Use the minimum testing needed to demonstrate an issue. If you encounter someone else's data, credentials or secrets, stop immediately, do not explore further or retain or share the data, and report the issue privately. A report should include the affected URL, reproduction steps using your own test data, and redacted evidence. Never include working credentials or customer data. We treat research that follows this policy as authorized under our Terms and will not pursue legal action against you for that research. This permission applies only to systems we operate; we cannot authorize testing on behalf of other parties. Please give us a reasonable opportunity to investigate and fix a reported issue before public disclosure. This policy does not offer a paid bug bounty. Report privately to [support@somewhere.tech](mailto:support@somewhere.tech?subject=Security%20report) with "Security report" in the subject; no account is needed. You can also use the in-product feedback channel (`support_ticket` via the MCP tools or Feedback in the dashboard). Mark sensitive reports as such. --- ## 10. Compliance & certifications - **SOC 2.** somewhere.tech uses platform, email, and payments services that maintain SOC 2; payment card processing uses a PCI-compliant service. The foundation under your app is audited and solid. We do not carry our own SOC 2 certification, and we're not pursuing one today — we'd rather be plain about that than imply otherwise. The controls described above are in place now. - **HIPAA / PHI.** Not intended for HIPAA-regulated protected health information, and we don't offer a BAA. - **PCI.** Card data is handled entirely by **Stripe** (Stripe Connect). Card numbers go directly to Stripe and never touch our servers, so PCI scope stays with Stripe — your app never handles raw card data. - **Support.** Every paid plan includes support from a small, hands-on team that's always on call — someone's reachable at all times and we troubleshoot with you directly, not through a ticket queue. - **Enterprise.** We're not set up for enterprise compliance, signed BAAs, SLAs, or formal procurement today. If those are hard requirements for you, we're honestly not your fit. If you want a reliable, fast backend with people who actually answer — that's exactly who we built this for. --- _For the complete platform reference (why every primitive exists and how they compose), see [/llms.txt](https://somewhere.tech/llms.txt). For the call-level API and every tool, see [/docs.txt](https://somewhere.tech/docs.txt). For how to take your data and code with you, see [/migration.txt](https://somewhere.tech/migration.txt)._