Skip to content

Security Model

The split that matters most: the platform owns the key, your code owns the broadcast. Everything in this page is a consequence of that split.

ThingWhereWhy
The private keyAWS KMS, never exportedKMS is FIPS 140-2 validated; raw key material is unreadable to humans and software alike.
The signing operationKMS Sign APIThe platform never holds your key in plaintext, even briefly.
Policy enforcementPre-sign gateCaps, allow-lists, and time windows are checked before the key is invoked. A blocked tx is never signed.
The mapping (projectId, userId) → walletPlatform DBLets you address wallets by your own user ID without storing addresses yourself.
ThingWhereWhy
The userIdYour DB / message queueThe platform stores it too, but you address wallets by your own ID — there’s no “platform user ID” you need to track.
The transaction recipient and valueYour application logicThe platform signs what you ask it to (within policy). It does not synthesize transactions on your behalf.
The nonceYour DB or live RPCThe platform has no view of your broadcasting state. Nonce tracking is yours.
The RPC endpointYour codeYou pick where the signed tx is broadcast. The platform never makes the network call.
The confirmation strategyYour codeBlock polling, websockets, fire-and-forget — entirely up to you.
┌─────────────────────────────────┐
│ Your Node.js server │
│ ─ holds API key │
│ ─ holds userId mapping │
│ ─ holds the chosen RPC │
└────────────┬────────────────────┘
│ HTTPS, signed with API key
┌─────────────────────────────────┐
│ 0xGasless API │
│ ─ resolves userId → wallet │
│ ─ enforces policy │
│ ─ calls KMS Sign │
└────────────┬────────────────────┘
│ AWS internal
┌─────────────────────────────────┐
│ AWS KMS │
│ ─ holds raw key material │
│ ─ never exports it │
│ ─ returns signed bytes only │
└─────────────────────────────────┘

There are exactly three places that can produce a signature:

  1. Anyone holding your API key can request signatures from the platform.
  2. The platform itself is the only caller permitted on KMS.
  3. KMS is the only system that ever touches the raw key.

If any of these is compromised the others limit the blast radius:

  • Stolen API key → attacker can request signatures from the platform, but every request still goes through your policy rules. Tight policies (per-tx cap, allow-list, time windows) make a stolen key much less valuable.
  • Compromised platform process → attacker can call KMS for any project’s wallets they can authenticate against, but cannot extract the underlying key material.
  • Compromised KMS → out of scope: the platform’s threat model assumes AWS KMS itself is not breached.

The project API key is the credential. Treat it like a database password:

  • Never check it into git. Use .env, KMS, Secrets Manager, or your platform’s secret store.
  • Never expose it to browser code. The SDK is for server-side use only.
  • Rotate it from the dashboard if you suspect leakage.
  • Set narrow policies in the dashboard so a leaked key has bounded blast radius.

A leaked API key gives an attacker the ability to call the platform on your behalf. They cannot exfiltrate private keys, but they can request signatures for any wallet in your project — bounded by your policies. The defense-in-depth is tight policies, not just key secrecy.

ThingWhy
Broadcast transactions.Sign-and-broadcast as a single platform action would centralize broadcast logic and make multi-chain support brittle. Keeping broadcast in your code means you choose the RPC, retry policy, and confirmation method.
Track nonces.Nonce tracking has to know what’s been broadcast. The platform doesn’t know — your code does.
Track balances.Same reason. The chain has the authoritative view; your code reads it.
Hold gas for you.Server wallets are EOAs. They pay their own gas in the chain’s native token. Top them up via the dashboard or any standard transfer.
Reveal the private key.KMS never exports raw key material. There is no “export to seed phrase” flow. If you need that property, server wallets are the wrong tool — use a self-custodial wallet instead.

For bot deployments, the typical end-user model is:

  • The user knows their wallet exists (you show them the address on /wallet).
  • The user doesn’t know there’s a key in KMS. From their POV the wallet is “their bot wallet”.
  • The user cannot sign with the wallet from outside your bot. There’s no seed phrase to export.
  • You enforce limits. Policies in the dashboard cap per-tx amounts, daily totals, and allowed recipients.

This is the right shape for Telegram bots, trading agents, and AI workers — environments where the human never holds the key in the first place. It’s the wrong shape for “give the user a key they can take elsewhere” — for that, use Embedded Wallets, where the key lives in the user’s browser.

Every server-wallet operation is logged in the dashboard:

  • Wallet creation (with userId, projectId, chain).
  • Sign requests (with target address, value, chain, policy decision).
  • Policy violations (with reason).

This is the audit trail you’d otherwise build yourself. Use it to monitor for runaway scripts, debug policy false-positives, and produce a paper trail for compliance reviews.