Security

Security

How we protect your data and our infrastructure

This is a self-assessment, last fully reviewed 2 June 2026 and updated 4 July 2026 to add the account-page nonce Content-Security-Policy and opt-in per-key origin restrictions. We review it quarterly and after any incident. EmergencyAPI is built by a solo operator on infrastructure that is independently certified. The sections below document what we do ourselves, what we rely on our providers for, and what we have not done yet.


Hosting and subprocessors

EmergencyAPI runs on third-party infrastructure that holds current SOC 2 Type II attestations. EmergencyAPI itself is not independently certified. We inherit these controls from our providers.

ProviderRoleAttestation
VercelAPI hosting, CDN, edge networkSOC 2 Type II
SupabasePostgreSQL, auth, row level securitySOC 2 Type II
GitHubSource control, CI/CDSOC 2 Type II

Data is encrypted in transit (TLS, via Vercel) and at rest (AES-256, via Supabase).


Authentication and access control

  • API keys are hashed (SHA-256) at rest and looked up by hash. The raw key is shown once and never stored.
  • Every key is gated by an active flag and an approved account status. Disabled keys and accounts are rejected.
  • Data endpoints use bearer API keys, not browser cookies, so they are not exposed to cross-site request forgery.
  • Keys can optionally be restricted to specific website origins, so a key embedded in a browser stops working if it is copied to another site. Server-side requests are unaffected.

Database security

  • Row Level Security is enabled on all application tables. Public-read tables are read-only to anonymous clients; all writes are service-role only.
  • User-owned rows are scoped by authenticated user ID. Direct user update paths are deliberately removed.
  • Privileged database functions have execute permission revoked from anonymous and authenticated roles. They run server-side only.
  • The Supabase security advisor reports 0 errors and 0 warnings. There are 2 informational notices: two internal lookup tables have RLS enabled with no policy, which means deny-all (no public access). Last checked 2 June 2026.

Rate limiting and abuse prevention

  • Durable, dual-layer rate limiting: an in-memory fast path backed by an atomic Supabase counter.
  • Monthly quota is enforced per account across all of a user's keys, race-safe via a database function with a unique constraint.
  • Authentication routes have separate IP-based limits (login and password change 5 per minute, signup 3 per hour).

Input validation

All query parameters are validated against allow-lists. Unknown enum values, malformed limits, and malformed bounding boxes return a 400 with a specific error rather than silently ignoring the filter. The proximity search radius is capped.


Transport and security headers

Responses set HSTS (one year, includeSubDomains, preload), a Content-Security-Policy with scoped allow-lists, X-Frame-Options DENY, X-Content-Type-Options nosniff, a Referrer-Policy, and a Permissions-Policy that locks down camera, microphone, and geolocation.

The account pages, where your session and API keys live, run a stricter nonce-based Content-Security-Policy with strict-dynamic and no inline-script allowance. The public pages keep a scoped allow-list policy that permits our own inline scripts, a deliberate trade-off that lets those pages stay statically cached. There is no user-generated content on the site, so the public pages carry no script-injection surface.

The public pages were independently graded B+ (score 80) by the Mozilla HTTP Observatory, 2 June 2026, reproducible at observatory.mozilla.org. The deduction is that inline-script allowance on the public policy.


Webhook and payment security

Stripe webhooks are verified by signature; unsigned or invalid events are rejected. Events are processed once via an idempotency table, so a replayed webhook cannot double-apply. Card data is handled entirely by Stripe and never touches our servers.


Secrets and supply chain

No environment files or secrets are committed to source control. The Supabase service-role key is used server-side only and is never included in the client bundle.


Data handling and privacy

  • We hold minimal personal data: your account email and API usage. Nothing more.
  • Incident data comes exclusively from official government emergency feeds and contains no end-user personal information.
  • We align with the Australian Privacy Act 1988. See the Privacy page.

Compliance

StandardStatusDetail
CAP-AU (Common Alerting Protocol)ValidatedAlerts and the cap-atom feed validate against the CAP-AU Profile v3.0 (Google CAP Validator)
AIDR Warnings Republisher10 of 12 satisfied2 partial. Full breakdown on the Compliance page
Supply NationRegisteredIndigenous-owned (Kokatha)
SOC 2 Type IIVia providersInherited from Vercel and Supabase, not an EmergencyAPI audit

For per-agency licensing status and the full AIDR self-audit, see the Compliance page.


What we have not done yet

Being honest about the gaps matters more than hiding them. As of June 2026:

  • EmergencyAPI itself has no independent SOC 2 audit. We inherit certified infrastructure but have not been audited as a company.
  • No third-party penetration test yet. We rely on the controls above, the Supabase advisor, and independent header grading.
  • No professional indemnity or cyber insurance yet. We will arrange cover when an enterprise contract requires it.
  • EmergencyAPI is built and operated by a solo founder. There is no 24/7 on-call team.

If you are evaluating us for a government or enterprise deployment and need any of these, get in touch. We would rather scope what you need than overstate what we have.


Responsible disclosure

If you find a security vulnerability, email jack@seysolutions.com.au. We acknowledge reports within 48 hours and work to resolve confirmed issues promptly. The same contact is published in our security.txt.


Contact

Security: jack@seysolutions.com.au