Built honestly.
Audit-ready in motion.
This page describes our security posture as it exists today, not as marketing aspires to it. Some controls are live, some are mid-migration, and a few are roadmap. We label them accordingly — every claim should hold up to a procurement review, a customer DPA addendum, or a 2 a.m. incident postmortem.
Most landscape software ships security as a marketing surface — RLS-on-the-box, “enterprise-grade,” SOC 2 banners that paper over the actual code. We're doing the opposite: shipping the architecture honestly, naming the gaps, and closing them in public on the changelog.
App-layer
Tenant scoping (RLS landing)
AI
Audit log live
TCPA
Consent gate ready
DPA
Public at /legal/dpa
Principles
Five things that are non-negotiable.
- 01
Your data is yours.
Exportable to CSV any day, by any admin. No data hostage. We will help you migrate OUT if you ever leave — full schema dumps, every table, every record, your format. The day you sign is the day we start earning the right to keep you, and a contract is not a substitute for a product worth keeping.
- 02
Multi-tenant by design.
Every record carries a tenant_id. Tenant scoping is enforced at the application layer — every server action and route handler reads the session cookie and filters every query by the authenticated tenant. Postgres Row-Level Security policies are also defined on every tenant table; we are migrating reads + writes from the service-role client to a per-tenant JWT'd client so RLS becomes the active boundary alongside application-layer scoping. Status: in progress, tracked on the roadmap.
- 03
No card data on our servers.
Stripe handles all card data. We never see, store, or transmit a primary account number. PCI scope = zero. When a customer pays an invoice through the Client Portal, the card never touches our infrastructure — it travels directly from the browser to Stripe's tokenization endpoint.
- 04
TCPA-aware messaging.
Consent is recorded as structured data, not free-text notes: every customer × channel has a row in customer_messaging_consent (status, source, consent text, version, IP, timestamps). Server-side canSend() check enforces opt-in status, per-tenant quiet-hours, and blocked weekdays before any dispatch. CSV import requires an attestation. Outbound auto-cadences ship behind this gate — never before.
- 05
Forensic AI audit trail.
Every Ask Gladius and AI Quote Drafter call writes a row to ai_run with tenant_id, surface, model, prompt hash + version, token counts (including cached), estimated cost in cents, and a 4KB output excerpt. When a customer asks 'what did your AI tell me three weeks ago,' we can answer with the exact response, model version, and prompt fingerprint that produced it.
Auth
Auth that an actual security team would approve.
We do not roll our own identity. We do not store password hashes. We rent the hard problem from the people who solve it full-time, and we audit them.
Magic-link auth
Tenants and operators sign in with a one-time link emailed via Resend. Tokens are HMAC-SHA256-signed with a per-environment secret, 15-minute TTL, single-use, rate-limited 5/hour per IP. No passwords on the operator-facing surface — phishing surface eliminated. SSO + SAML on the enterprise roadmap.
Role-based access
Three roles today: tenant owner, tenant member, founder. Owners get full workspace access; members are reserved for upcoming team-seat features; founders have cross-tenant read access for support, disclosed in /legal/privacy §2.5 and migrating to per-incident opt-in grants.
Session security
Cookies are HttpOnly + Secure + SameSite=Lax with HMAC-signed payloads. Session TTL is 7 days; the cookie revalidates on every request against the tenant_invitations table so a revoked owner loses access on the next page load. Production hard-fails if the tenant session secret env var is missing.
Founder access transparency
When founders read a tenant's workspace for support, the access is disclosed in the privacy policy and we are shipping a per-tenant opt-in grant system so the tenant explicitly authorizes each support session. Until that ships, all founder cross-tenant reads are restricted to two named individuals on file.
Isolation
Two layers between any two crews' data.
Every tenant-owned row in the database carries a tenant_id foreign key to tenants. The column is not nullable, the FK cascades on tenant deletion, and the application layer fills it in from the authenticated session — never from client-supplied input.
- Layer 1 — application (live)
Every server action and route handler under
/app/(authed)reads the signed session cookie viareadAppSession(), assertssession.kind === "tenant", and filters every query bytenant_id. This is the active boundary today. - Layer 2 — database (in progress)
Row-Level Security policies are defined on every tenant table — they will become the active second boundary once we finish migrating server-side reads + writes from the service-role client to a per-request JWT'd client. Until that lands, RLS is a defense-in-depth backstop, not a primary boundary.
- Layer 3 — tests (roadmap)
A cross-tenant leak suite that spins up two synthetic tenants and asserts neither can read the other's rows on every release. Lands alongside the RLS migration above.
Request lifecycle
Browser
HMAC-signed session cookie · tenant_id = bright-lights
Layer 1 — server action (live)
readAppSession() · .eq("tenant_id", session.tenant.id)
Layer 2 — Postgres RLS (migrating)
USING (is_tenant_member(tenant_id)) · activates once reads move off service-role
Tenant A
Lighting shop
Tenant B
Irrigation crew
Two silos. No shared rows. Ever.
Compliance
Where we are. Where we're going.
Public roadmap. We update this page when an item ships, when an audit closes, when a date slips. No vapor.
Done now
PCI scope = 0 (Stripe-tokenized; no PAN ever touches us)
Encryption at rest + in transit (Supabase-managed, TLS 1.2+)
Per-tenant scoping at the application layer
TCPA consent ledger + send-time canSend() gate
AI run audit log (model, prompt hash, tokens, cost, output)
Data Processing Agreement at /legal/dpa
In progress
RLS as the primary security boundary (per-tenant JWT'd client)
Per-tenant opt-in grant for founder support access
SOC 2 Type II audit (target Q4 2026)
Outbound auto-cadence behind the consent gate
Roadmap
External penetration test (twice yearly)
California CCPA portal
ISO 27001
Pesticide license verification (regulated chemicals engine)
Disclosure
We pay for security research.
If you've found a vulnerability — anything from a cross-tenant leak to an authentication bypass to a TCPA consent loophole — please report it. We will not sue you, we will not threaten you, we will thank you, and if the finding holds up we will pay you.
Our SLA: initial response in 24 hours, triage decision in 72 hours, fix or mitigation timeline communicated within seven days. Critical findings get a same-day patch and a public post-mortem when the dust settles.
A formal bug bounty program is in active development with a third-party platform. Until it's live, contact us directly and we'll handle reward and disclosure one-on-one.
Security inbox
security@gladiusturf.comPGP key
4096R / AB12 CD34
Full key on request — reply to the address above and we'll send the armored block.
Response SLA
- 24h — initial human response
- 72h — triage decision
- 7d — remediation timeline
Legal
DPAs and MSAs available.
Procurement-friendly. We don't hide the contracts behind a sales conversation.
- Request →
Master Services Agreement (MSA)
PDF — request via email
- Request →
Data Processing Addendum (DPA)
PDF — request via email
- Request →
Privacy Policy
Public — gladiusturf.com/legal/privacy
- Request →
Terms of Service
Public — gladiusturf.com/legal/terms
All available pre-purchase. Email legal@gladiusturf.com to receive.
Stop losing the revenue
your software is missing.
Switch in 48 hours. Keep your QuickBooks. 30-day money-back guarantee.
The first leak we close usually pays for the year.
