Skip to content

Security model

A short, honest pass over what Naasson protects, what it doesn’t, and where the seams are.

What we sign

  • Session JWTs — HS256 signed with JWT_SIGNING_KEY held in Lockbox. 24-hour TTL. Bound to Subject = user_id.
  • Agent tokens — random 32 bytes. We store only sha256(token); the cleartext is shown to the user once on creation and never recoverable. The edge authenticates each agent dial-in by hashing the presented token and comparing.
  • Edge-handoff JWTs — 30-second TTL, single-use, signed by the same key. Used to bounce a logged-in user from api.cloud.naasson.com to a *.cloud.naasson.com FQDN with a fresh per-FQDN cookie.
  • Wildcard TLS*.cloud.naasson.com from Let’s Encrypt via ACME, auto-renewed by a cron on each edge node that pulls from Yandex Certificate Manager into Lockbox.

Trust boundaries

You trustWe trustOut of scope
Your own hostThe cleartext payload of an agent token, exactly onceThe hosts of other rental providers (Mode 3)
The browser session cookie scoped to one FQDNYDB row integrity for tunnel_routes and tunnel_agentsThe contents of WASM sandboxes (Mode 5, deferred)
The wildcard cert chainA valid OAuth response from Yandex/Google/GitHubHosts running unknown rented workloads

What stops cross-user impersonation

Two checks, deployed 2026-05-16:

  1. POST /tunnel-agents verifies that workspace.user_id matches the caller’s claims.subject. Without this, any logged-in user could mint an agent token for any workspace they happened to know the ID of. Returns 404 (not 403) on mismatch so workspace IDs stay unprobeable.
  2. POST /tunnel-routes verifies the same for both workspace and agent. Even when the caller owns both objects, the route’s workspace must match the agent’s workspace — preventing cross-workspace “I own a vanity name pointing at your service” attacks.

Cross-user attempts are warn-logged for forensic review.

What stops a malicious workload reaching your host

The agent forwards bytes to localhost:<target_port>. It does not:

  • exec shell commands from edge frames;
  • write to the filesystem;
  • inspect or modify the payload;
  • access more than the one port you named when creating the route.

The systemd unit drops to a dedicated naasson system user, with ProtectSystem=strict, ProtectHome=true, NoNewPrivileges=true, and MemoryDenyWriteExecute=true. The agent has no read access to your home directory or any other user’s files.

What we don’t read

  • The bodies of requests through the edge. TCP passthrough; we see the TLS-encrypted bytes only as bytes.
  • Your workspace state. The blob state_json on a workspace row is treated as opaque.
  • Your cloud provider credentials. When you connect a Yandex/AWS/ GCP account to a workspace, the API tokens flow through the worker pipeline and into a per-deploy ephemeral env — never written to YDB or to logs.

What’s deferred

  • WASM sandbox audit-by-hash for Mode 5 batch — we sign the manifest hash and a host that runs the workload commits to that hash, but the runtime enforcement story is still being designed.
  • mTLS client certs in the browser (auth_mode=cookie+mtls) — drafted in R5.2 but not yet wired.
  • HSM-backed JWT signing. Today the key is in Lockbox, which is itself encrypted; the next step is to move the signing operation inside a hardware module.

How to report

Security issues go to security@naasson.com. Please don’t open public issues for things that affect cross-user data — give us a window between report and disclosure. We don’t run a bug bounty yet, but we will publicly thank you.