Security
The server never sees
what you don't keep
Stubsmith turns real API traffic into deterministic integration tests. Masking happens at the edge, inside your infrastructure, before any data is transmitted. Only the fields you reviewed and gave a keep rule reach our servers in the clear, and by default there are none. This page explains how that works in practice.
Edge-only masking
Samples are masked at the SDK, inside your infrastructure, before any network call is made. The Stubsmith ingest endpoint receives masked bodies and field names. A raw value from your users crosses your network boundary only for a scalar field you reviewed and gave an explicit keep rule, and by default no field has one.
This is the fundamental privacy guarantee: we never see a value you have not explicitly kept, by construction. It is not a firewall policy, an RBAC rule, or a contractual promise: the server receives only masked payloads, in which every value not covered by a keep rule you approved has been replaced before leaving your process.
The SDK applies your masking rules fail-closed: every value is hidden unless a keep rule explicitly permits it. By default a string becomes <masked>, a number becomes 0 and a boolean becomes false. Set STUBSMITH_MASK_SALT and masked values keep their shape instead: a UUID stays a parseable UUID, a timestamp stays ISO 8601, an amount stays a non-zero decimal, each derived from the real value so equal values still match and different ones still differ. A new field in an API response is masked automatically until you configure a rule for it.
What crosses the boundary
Two things leave your infrastructure and reach Stubsmith's ingest endpoint:
- Masked sample bodies: the request/response body after masking rules have run. Values have been replaced with placeholders of the same type. The
amountfield is0, or a non-zero decimal once format-preserving placeholders are enabled. Thereceipt_emailfield is<masked>, or a synthetic address on your placeholder domain. Thebilling_namefield is<masked>either way: there is no name-shaped placeholder, so the most it can become is a synthetic token. Structure and key names are preserved; content is gone. - Structural fingerprints: each fingerprint’s identity is the request method and path template, keyed to a blake2b-64 digest over the sorted key-paths, query-parameter names, and content type. No values enter the digest. Fingerprints are how Stubsmith deduplicates traffic and organizes stubs. Your endpoint names, HTTP methods, and path templates are visible; response schema shapes are recorded alongside fingerprints but are not digest inputs; what your users sent is not visible.
Field and path names are visible to Stubsmith. If your API path structure encodes sensitive information (for example, /users/{email}/profile), that structure is visible in fingerprints. Values are not.
Review and approval in the Stubsmith app operates on field names and paths, not on real values from your users.
EU-sovereign infrastructure
Every system that handles your captures, stubs, and account data runs in the European Union. Email is the one exception and is hosted in Switzerland, a country the European Commission recognises as providing an adequate level of data protection. No data transits to or is processed by US-headquartered cloud providers.
Compute: UpCloud, Amsterdam
The API, ingest, and web services run on UpCloud infrastructure in the nl-ams (Amsterdam) region. UpCloud is a Finnish company; infrastructure stays in the EU.
Object storage: Scaleway, Amsterdam
Masked sample bodies are stored in Scaleway object storage in the nl-ams (Amsterdam) region. Scaleway is a French company; data stays in the EU.
Email: Infomaniak, Switzerland
Email for stubsmith.dev is hosted by Infomaniak, a Swiss company, in its own datacentres in Geneva and the canton of Vaud. Switzerland holds an EU adequacy decision, so no additional transfer safeguards are required. Correspondence only: no captures, stubs, or sample data ever reach a mailbox.
DNS and CDN: Bunny.net
DNS is operated by Bunny.net, a Slovenian company. Bunny.net also serves the public static surfaces via CDN: the marketing site (stubsmith.dev), the documentation site (docs.stubsmith.dev), and dashboard static assets (static.stubsmith.dev). Bunny.net terminates TLS for those public surfaces. The dashboard application (app.stubsmith.dev), the API, and the ingest endpoint (ingest.stubsmith.dev) are not behind the CDN: their TLS is terminated by Caddy (Let's Encrypt) on the application host, so authenticated traffic, API requests, and captured payloads never pass through the CDN. We deliberately avoided Cloudflare (US, subject to the CLOUD Act); Bunny.net is EU-based.
Database: UpCloud Managed PostgreSQL
Customer data is stored in UpCloud Managed PostgreSQL in the nl-ams (Amsterdam) region. The database has no public endpoint and is reachable only over a private network.
Sovereignty footnote: the .dev TLD registry is operated by Google. This is a paper-level dependency; the registry sees domain registration metadata, not user data or traffic.
Fail-closed fingerprints
A fingerprint is one unique traffic shape on one endpoint. Its key is the request method and path template plus a blake2b-64 digest over the request’s sorted key-paths, query-parameter names and content type. It records structure and names only, never values.
Fingerprints are capped per plan. When the cap is reached, new shapes are rejected at ingest with a clear error and a dashboard banner. The cap is enforced at ingestion time, not retroactively. Existing fingerprints and their stubs are never deleted.
Fingerprints are your durable asset. Samples (masked sample bodies) are kept as a rolling window per response variant, sized by your plan: the newest are retained and older ones are deleted as new samples arrive. The window is a count rather than an age, so an endpoint that fires rarely keeps its samples for as long as the fingerprint exists. Fingerprints, request types, and generated stubs persist indefinitely.
Tenant isolation baseline
The following controls are standard requirements for any multi-tenant system. They are listed for completeness, not offered as differentiators.
- Fail-closed RLS
- The runtime database role has no
BYPASSRLSprivilege. Every tenant query runs in a transaction that setsorg_id = current_setting('app.current_org'); a missing or invalid context returns zero rows, never another tenant's data. Tables useFORCE ROW LEVEL SECURITY, so even the migration owner role obeys the policies. - Transaction-scoped context
- The org context is set via
set_config(..., true), a transaction-local GUC that clears automatically at transaction end. No cross-request leakage is possible. - Encryption in transit
- Every public endpoint is HTTPS only. TLS for the dashboard, the API and the ingest endpoint is terminated by Caddy (Let's Encrypt) on the application host; the public static surfaces are served over TLS by Bunny.net.
- Database encryption at rest
- The database runs on UpCloud Managed PostgreSQL, which encrypts its volumes at rest with a per-instance key and encrypts its backups separately, stored off site. This protects the database; it is not what protects your users' data, which is masked before it ever reaches us.
- App-level filters
- Application queries also carry explicit
WHERE org_id = ?predicates. RLS is the database-enforced backstop; app-level checks are the primary filter. Defense in depth.
Security FAQ
- Does Stubsmith see my API request/response bodies?
- Not unless you ask us to. The SDK masks every request and response body fail-closed: values are replaced with typed placeholders before anything leaves your infrastructure. Stubsmith receives masked bodies and field names. The only values that arrive in the clear are those on fields you reviewed and gave a keep rule, and by default there are none. Everything else our staff cannot see, because it never left your process; this is a structural guarantee, not a policy promise.
- What exactly does Stubsmith receive?
- Two things cross the boundary: masked sample bodies (every value replaced by a placeholder of the same type: strings become <masked>, numbers become 0, booleans become false) and structural fingerprints (the key-paths, header names, and query-parameter names that describe your API shape). The actual values your users sent or your API returned do not reach our servers, with one exception: a scalar field you reviewed and gave a keep rule arrives as it was sent.
- What happens to my data when I cancel?
- Samples are kept as a rolling window per response variant, sized by your plan, and the oldest are deleted as new ones arrive. Fingerprints and stubs persist until you delete them or close your account. You can request immediate deletion of all sample data by contacting support.
- How does PostgreSQL RLS protect my data?
- Every tenant query runs inside a transaction that sets an org_id context variable. RLS policies check this variable; a query without a valid context returns zero rows. The runtime database role has no BYPASSRLS privilege, fail-closed by design.
- Is my data encrypted?
- In transit, yes, everywhere: every public endpoint is HTTPS only, and the SDK will not post to a plaintext endpoint. The database is UpCloud Managed PostgreSQL, which encrypts its volumes at rest and encrypts its backups separately, off site. For sample bodies the stronger property is that there is nothing to decrypt: values are replaced at the SDK, so what is stored is masked structure, not content. The exception is a field you reviewed and gave a keep rule, which is stored as it was sent.
- Where does my data physically reside?
- Compute runs on UpCloud infrastructure in Amsterdam (nl-ams); the database is UpCloud Managed PostgreSQL in the same region. UpCloud is a Finnish company. Object storage is on Scaleway in Amsterdam (Scaleway is a French company). DNS is operated by Bunny.net in Slovenia; Bunny.net also serves the public static surfaces (marketing site, documentation, dashboard static assets) via CDN, though the dashboard application, API, and ingest endpoint are not behind the CDN. Email is hosted by Infomaniak in Switzerland, which holds an EU adequacy decision. No data is processed by US-headquartered hyperscalers.
- Can I verify the security architecture independently?
- The SDK is open source and the masking path is auditable. The anonymizer rule format and the fingerprint schema are public. A third-party security audit is on the roadmap before the first Business-tier customer signs.
Privacy by construction, not policy
Start with the free plan. No card required.