MainSDK
Search⌘K
Docs

Security model

How MainSDK keeps keys out of code, limits who your app talks to, redacts what it writes and signs what it ships and delivers.

Updated 2026-10-28

MainSDK's security rests on one rule: if it touches data, the network, money, messages, AI or identity, it goes through MainSDK. Every sensitive call then has one place where it is checked, decided and recorded. This page covers the parts that protect your app as a whole.

Secrets are references

Keys never appear in code or in main.yaml. You refer to them as secret:NAME, and the secrets driver resolves them on the server at startup, from a cloud key service, Vault, Doppler or Infisical, preferring workload identity over static tokens.

main.yaml
secrets:
  driver: vault
  vault: { address: https://vault.pinecart.internal, auth: workload-identity }
db:
  driver: postgres
  regions: { us: secret:DATABASE_URL_US, eu: secret:DATABASE_URL_EU }
files:
  driver: getqr
  key: secret:GETQR_API_KEY
app/lib/partner.ts
import { secrets } from "mainsdk";   // server only: a client import fails the build

const token = await secrets.get("PARTNER_API_TOKEN");

The check fails on a key pattern in source (MAIN-SECRET-0002), a committed .env other than .env.example (MAIN-SECRET-0003), a secret in the browser bundle (MAIN-SECRET-0004), a client import of secrets (MAIN-SECRET-0001) and a literal in a secret field of main.yaml (MAIN-CONFIG-0004). Resolved values are marked for redaction everywhere. See secrets.

Network permissions

Like a phone app's declared permissions, your app lists the destinations it may reach. Anything else is blocked and reported.

main.yaml
network:
  allow:
    - 10.20.0.0/16     # a range
    - google.com       # exactly this domain
    - "*.pinecart.dev"     # its subdomains only
  default: deny
  mode: enforce        # observe | warn | enforce
  • Drivers declare their own hosts, so the list holds only your destinations.
  • Enforced in the SDK's network layer for every outbound call. DNS answers are checked (no rebinding to private ranges), and redirects to undeclared hosts are refused (MAIN-NET-0003).
  • mainsdk check blocks raw sockets, other HTTP clients and direct fetch outside the SDK at build (MAIN-NET-0001).
  • A poisoned dependency that sends secrets to a new domain fails in CI and is blocked and reported in production (MAIN-NET-0002).
  • mainsdk network export --to vercel|k8s|aws-sg|cloudflare writes the same list as platform rules for a second, independent wall.

Network permissions run inside your app and are free on every plan. See network.

Redaction before anything is written

Redaction runs in process before any log, error or export:

  • values of fields labelled personal, sensitive, child or phi (see data labels);
  • anything resolved from a secret: reference;
  • known key formats, such as msk_live_ and msk_test_.

By default MainSDK doesn't collect request or response bodies, cookies, or authorization, cookie and set-cookie headers. User IDs are pseudonymised with a keyed hash per project before export, and IP addresses are trimmed (IPv4 /24, IPv6 /48). The telemetry contract telemetry@1 lists every field collected and its purpose; a field not in it is never exported.

text
2026-10-25T10:14:03Z ERROR MAIN-DATA-0007 orders.get for another user's order
  user.id=h_5c1a…  email=[redacted:personal]  key=[redacted:secret]

Problem details returned to end users never include file, line or stack in production; those stay in your logs. See Errors.

The audit log

Every policy decision, sign-in, key use and erasure is written to an append-only, tamper-evident audit log in OCSF. Each record carries the hash of the previous one, so log.audit.verify() detects any edit, deletion or reorder. The audit log is never sampled.

Signed releases and safe delivery

WhatHow it's protected
MainSDK's own packagesSigstore signatures, SLSA level 3 provenance, reproducible builds, an SBOM, no install scripts, few dependencies pinned by hash
Your releasesSigned builds and SBOM per release; the Main mark records provenance at /.well-known/mainsdk.json
Driver versionsResolved into main.lock with SHA-256 hashes
Baseline packs, market packs, driver metadataDelivered through The Update Framework (TUF): an offline threshold root, snapshot and timestamp roles, so a replayed old pack (MAIN-TUF-0001 rollback) or a hidden newer one is refused

When delivery metadata expires and the mirror is unreachable, your app keeps its last good pack and logs MAIN-TUF-0004 stale. It never blocks a request; see Never in the request path. Delivery internals are in Supply chain.

Sign-in and admin access

Passkeys are the default for your users; passwords are a fallback you can turn off. Admin roles must use passkeys or SSO with phishing-resistant MFA, or the check fails. See auth.

Access to production through MainSDK Cloud (live tail, debug sessions, Fleet critical actions) needs SSO and MFA, plus step-up authentication, and every use is audited. MainSDK never offers a remote shell or debugger into production.

Disclosure and support

Critical vulnerabilities are fixed within 7 days and high within 30, with advisories and CVEs. Each baseline has a long-term support line of at least 24 months. Every interface and driver class has a published STRIDE threat model, versioned with its contract. How these pieces fit together inside MainSDK is in Security architecture.

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet