About

Trust and security

Macro by Mark handles account credentials, billing identity, and research workflows for economists, students, professors, and institutional users. This page documents the controls actually shipped and the providers your data flows through.

Last reviewed: 2026-05-13.

Live stats

Aggregate counts refresh every 6 hours. No per-user data; only coarse activity and posture indicators. Fields that are unavailable render as "n/a".

MFA adoption
n/a
Passkey adoption
5%
Active sessions
95
Sign-ins last 24h
5
Unacknowledged anomalies (7d)
0
Service-role allowlist size
69

Snapshot generated Tue, 26 May 2026 10:46:47 GMT.

Account security

Sign-in uses Auth.js v5 with password, Google OAuth, and first-factor passkeys. Supabase Auth backs account identity. Browser code never receives Supabase bearer tokens; account routes call Supabase server-side from inside the encrypted Auth.js JWT.

  • Passkeys (WebAuthn). First-factor sign-in with platform authenticators (Touch ID, Face ID, Windows Hello, hardware keys). Verified server-side via @simplewebauthn/server. A passkey sign-in lands the session at AAL2 immediately because the credential is phishing-resistant; no follow-up TOTP prompt. Counter regression on a verify is treated as a clone signal and the assertion is refused.
  • TOTP MFA. Time-based one-time password via any standard authenticator app. Verified TOTP factors gate sensitive routes through an AAL2 enforcement middleware. Recovery codes (10 single-use, 55 bits of entropy, hashed with scrypt N=2^15) are generated once at enrollment and shown to the user; we never store plaintext.
  • Captcha protection. Sign-in, sign-up, and password reset require solving a Cloudflare Turnstile challenge. Tokens are single-use and bound to the request that consumes them.
  • Account-keyed throttle. Sign-in attempts are capped at 8 per 15 minutes per email (lower-cased) on top of the IP rate limit. The bucket key is hashed before persistence, so the throttle table never sees plaintext addresses.
  • Breached-password refusal. Sign-up and password change run a HaveIBeenPwned k-anonymity lookup before forwarding to Supabase. Only the first 5 hex chars of SHA-1 leave the server, so HIBP cannot identify the candidate. Network errors fail open; the lookup is a guard, not a single point of failure.
  • Session lifetime. Sessions roll forward on activity for up to 30 days, with the JWT re-encoded after one hour of idle. Admin proof additionally expires after 8 hours; admin actions require re-auth past that window even if the normal session is still valid.
  • Step-up verification. Password change, email change, account delete, billing portal entry, and passkey removal require a fresh password, passkey, or authenticator proof. The step-up cookie is HMAC signed and lasts 10 minutes.
  • Active session inventory.Each sign-in registers a row tied to your account JWT. You can see active devices in Account > Security and revoke any session, including sign-out-everywhere.
  • Sign-in alerts. When a sign-in fingerprint is new for your account and the browser has not been trusted by a prior completed sign-in, an email notification dispatches automatically.
  • Mandatory MFA for admin accounts. Admin entitlements cannot be exercised without a verified TOTP factor and a fresh (within 8h) admin proof.

Network and platform controls

  • Content Security Policy. Production drops'unsafe-eval' entirely. A per-request nonce mechanism is in place to migrate off'unsafe-inline'; trusted inline scripts (JSON-LD, hydration) carry the nonce.
  • Strict-Transport-Security. Production setsmax-age=31536000; includeSubDomains; preload.
  • Rate limiting. Auth-sensitive routes (sign-in, register, password reset, password change, email change, account delete, verify-password) use a distributed Upstash limiter that degrades to a per-instance in-memory limiter on outage instead of failing open.
  • Server authorization boundary.User-facing account routes use Supabase clients scoped to the caller's JWT, so row-level security is the actual authorization gate; the explicit user_id filters in code are defense in depth.
  • Service-role drift guard. The set of files that can call Supabase with the privileged service-role key is a typed allowlist with per-entry reasons. A CI test walks the repo and fails if any file outside the list imports the service-role client. Adding a new privileged caller is a deliberate, reviewable diff.
  • Log redaction. Server-side logs route structured payloads through a sanitizer that masks emails (ma***@domain), strips password / token / cookie / authorization keys, truncates oversize values, and breaks circular references. Stack traces are gated behind LOG_LEVEL=debug.

External controls verification

We maintain an external security-probe runner for HSTS, CSP, cookie flags, TLS, and session-boundary checks. Scheduled and post-deploy probe workflows are currently manual-only while CI minutes are constrained; when a probe runs, it checkpoints results here. The last 24 hours of checkpointed results:

Probe runs (24h)
0
Pass rate
(no runs yet)
Last run
(none)

Probe reports are available to institutional reviewers on request. If the public page cannot read the checkpoint store, this section reports no recent runs rather than claiming a passing control.

Data minimization and persistence

  • Onboarding identifying fields (city, school, organization, region, professional metadata) live server-side under owner-only RLS with a 7-day TTL on the draft. Pre- verification, the wizard runs in memory only; nothing identifying persists to your device.
  • Phone numbers are not collected pre-verification. The onboarding form no longer asks for a phone number. If a future feature requires it, the field will appear in account settings post-sign-in, never on the onboarding gate.
  • Browser localStorage stores only non-PII UI preferences: focus areas, experience level, marketing opt-in, notification preferences, and the disclosure flag.
  • Cookie consent gates analytics. Vercel Analytics and Speed Insights only mount after the consent banner records an explicit analytics: granted decision. Server-render returns no tracker tags; first client paint also returns nothing until the persist middleware rehydrates the decision. Revoking mid-session unmounts the trackers.

Marco assistant controls

  • Server-side plan checks. The chat route resolves entitlement on the server, applies the tier rate limit before the model provider is called, and keeps first-name sanitization on the server path.
  • Source-bound answers. Marco classifies each request before generation. Current values, release dates, news items, forecast results, dashboards, watchlists, and workspace records require source cards for that request. Missing source context produces a limited answer instead of a made-up number or date. Release cards also mark whether actual, prior, consensus, and surprise fields are present, partial, or unavailable.
  • Private saved records. Dashboard and watchlist context, plus workspace notes, projects, and saved runs, are read only when the user is signed in and asks for that private context. Reads use a user-scoped Supabase token, RLS, and an explicit user_id filter. Marco receives compact source summaries and capped workspace snippets, not raw dashboard configuration.
  • Preference context. Marco may use the current locale and signed-in profile fields such as timezone, country, experience level, and focus areas to choose reply language, formatting, explanation depth, and examples. It does not receive raw cookie values, analytics history, marketing signals, or private saved records through this path, and preference context is never a source for live data claims.
  • Saved chat history. Signed-in Marco conversations are stored as one capped account row in Supabase. Visitors keep tab-local history only, and the chat header includes a clear control for the saved conversation.
  • Safety boundary. Marco can explain macro conditions and risk channels, but it must not provide personalized buy, sell, hold, trading-signal, or portfolio-allocation advice.

Your data, your access

  • Export. Sign in and call /api/account/export. You receive a JSON bundle of every owner-scoped row we hold: profile, preferences, dashboards, watchlists, notifications, workspace, sessions, security events, watchlist alert subscriptions, personal access token metadata, security anomalies, and billing subscriptions. Schema-versioned for stable diffing.
  • Delete.Account > Security > Delete account. Step-up gated with password, passkey, or authenticator and confirmed with the literal word DELETE. Cascade removes profile, preferences, dashboards, watchlists, notifications, workspace, onboarding draft, sessions, passkeys, personal access tokens, MFA factors, and recovery codes. Billing records have separate retention obligations and are scrubbed on a separate schedule.
  • Correct.Account > Settings to edit profile fields. Account > Security to rotate password or email.

Subprocessors

The product depends on the following third-party providers. The table lists the purpose and data classes involved in the live request path. Material subprocessor changes are emailed to active paid users at least 30 days before they take effect.

ProviderPurposeData
SupabaseAuthentication and primary databaseAccount identity, profile, preferences, sessions, MFA factors, passkeys, saved account records, and saved Marco conversations
VercelApplication hosting, serverless runtime, and edge deliveryRequest metadata, IP address, user agent, URL, response status, and runtime logs
Upstash RedisDistributed rate limiting and cache storage when configuredRate-limit keys, IP-derived buckets, counters, reset timestamps, and public macro cache payloads
AnthropicMarco assistant model providerAssistant messages, page path, source context, tier/model metadata, limited profile context, and explicit saved-object summaries when the user asks for them
StripePayments, subscriptions, invoicing, and customer portalEmail, name, billing address, payment-method tokens, invoice records, and subscription metadata
ResendTransactional emailEmail address, delivery metadata, and the message content needed for sign-in alerts, password flows, and notifications
CloudflareTurnstile bot challenge and DNSIP address, browser context, and challenge solve evidence
GoogleOAuth identity providerEmail, name, profile picture URL, and Google subject claim
Trigger.devBackground job runtime for ingestion and lab pipelinesIndicator catalog data, lab run results, queue metadata, and job state
Tiger Cloud / TimescaleTime-series storage for the macroeconomic indicator discovery catalogPublic macroeconomic catalog metadata and observation rows
SentryError monitoring when configuredStack traces, user id, URL, and basic request metadata after redaction

See the standalone subprocessor list for region notes and institutional-review wording.

Retention map

DataRetention
Profile and preferencesUntil account deletion. Restored from export bundle if requested.
Dashboards, watchlists, and workspace recordsUntil account deletion or until you remove the record sooner. Included in account export.
Saved Marco conversationsSigned-in accounts keep one capped row with the latest 40 UI messages by default for 90 days; clearing chat or deleting the account removes it sooner.
Notifications and alert subscriptionsUntil account deletion, unsubscribe, or preference removal. Delivery-provider logs follow the provider retention policy.
Onboarding drafts7 days from last write or until onboarding completes, whichever is first.
Active sessionsUntil you sign out, until you revoke them, or 90 days idle (whichever is first).
Security events365 days, then automatically purged.
MFA recovery codes (hashed)Until consumed or until you re-enroll MFA.
Billing recordsRetained per applicable financial law (typically 7 years), separate from account deletion.

Compliance documentation

The following operational runbooks back the controls listed above. They are maintained alongside the underlying systems and are available on request for vendor reviews and procurement questionnaires:

  • Data subject access requests (GDPR Art. 15 / 17 / 20, CCPA).
  • Incident response (SEV1-4 matrix, IC role, 72-hour regulator notification window).
  • Privileged access review (quarterly cadence, off-boarding ladder).
  • Subprocessor list with data classes and 30-day pre-announce policy.
  • Backup and restore (RPO / RTO targets, drill cadence).

For institutional buyer evaluations, see the consolidated procurement pack.

Reporting and contact

For privacy requests, vulnerability disclosures, or DPA inquiries:

We aim to acknowledge privacy and DPA requests within two business days and to fulfill them within 30 days where law applies. Vulnerability disclosures are acknowledged within five business days.

See also our privacy policy and terms of use.