Security commitments.
AES-256-GCM for secrets. RLS on every tenant table. Default-deny outbound HTTP. SHA-256 hashed API keys.
AES-256-GCM for secrets. RLS on every tenant table. Default-deny outbound HTTP. SHA-256 hashed API keys.
TL;DR
Skill Packs are executable code running on a buyer's behalf. That makes security a product feature, not a compliance afterthought. We document our actual controls below - what's in production today, not aspirations.
Found something concerning? Email security@selrgroup.com.au - see responsible disclosure for the bounty policy.
1. Encryption
- In transit: TLS 1.3 enforced on every public endpoint via Vercel and Cloudflare edge. HSTS preload with
max-age=63072000. - At rest, application data: Supabase Postgres with encrypted disk volumes.
- At rest, buyer secrets: AES-256-GCM column encryption via Supabase Vault. Each secret has a unique encryption key id and per-secret nonce. Decryption only inside the sandboxed runtime at execution time.
- Object storage: Cloudflare R2 with server-side encryption using R2-managed keys.
2. Row-level security
Every tenant table in our Supabase database has row-level security policies enforced at the Postgres layer. Application code cannot read or write rows owned by another account, even if a query is malformed.
We run a multi-tenant RLS test suite on every PR. It attempts cross-tenant reads and writes from a probe account and fails the build if any of them succeed.
3. Sandboxed runtime
Hosted-mode Skill Packs run inside e2b.dev sandboxed micro-VMs. Each invocation:
- Cold-starts from a warm pool (target p50 cold start: 218ms) into an isolated VM with no network access by default.
- Reads only the egress allow-list declared in the pack's
permissions.outbound_http.allow. Wildcards are forbidden at manifest parse time. - Has a hard wall-clock timeout (default 30s) and a memory cap (default 512MB). Configurable in the manifest within Platform-defined ceilings.
- Has a per-buyer, per-pack spend cap when the optional hosted runtime is enabled (it is currently off; skills run in the buyer’s own agent).
- Is destroyed after invocation. State must be persisted via declared manifest resources, not on-disk in the VM.
4. API key handling
- SHA-256 hashed at rest. We never store plaintext API keys in the database. Only the hash and a 6-character prefix (for human recognition).
- Plaintext shown ONCE. When you mint a key in your dashboard, the plaintext appears one time on screen. You must save it immediately. Lost keys cannot be recovered - only revoked and replaced.
- Scope-restricted. Each key carries an explicit scope set (
read:installs,read:usage,write:webhooks, etc). Minimum-privilege by default. - Per-key revoke. Revoke any individual key without affecting your other keys.
5. Skill Pack supply-chain review
Every Skill Pack is treated as a third-party package. Before publication:
- Static scan via Semgrep. We run pattern matches against the source for known malware signatures, credential exfiltration patterns, and prohibited capability usage.
- Manual human review at launch. Every pack is reviewed by a human moderator before going live. We will automate parts of this as volume grows, but the human gate stays for high-risk classifications indefinitely.
- Per-skill permission declaration. The manifest must list every capability the pack uses. Buyers approve each capability on install.
- Emergency revoke. Loup can instantly disable any pack across all buyers if a security issue is found after launch.
6. Buyer secrets
When a pack you install needs your API key, OAuth token, or other credential:
- You enter it on a dedicated buyer-secrets page in your dashboard. The page posts directly to a server endpoint that immediately encrypts the value using AES-256-GCM via Supabase Vault. The plaintext is held in process memory only for the duration of the encryption call.
- At pack execution time, the runtime requests the decrypted value over a short-lived authenticated channel. The decrypted value lives in the runtime VM only for the duration of execution and is destroyed when the VM is recycled.
- We never log decrypted values. We never include them in support tickets, error reports, or analytics.
- On account deletion, encrypted secrets are erased per the retention policy. Encryption keys are rotated periodically.
7. Incident response
- On-call rotation with paging for severity-1 and severity-2 incidents.
- Status page at /status updates within 10 minutes of a confirmed incident.
- 72-hour breach notification window to affected customers per GDPR Article 33 / equivalent. Notifications include scope, likely impact, and our response.
- Post-incident review published as a public changelog entry within 7 days of resolution unless legal counsel advises a delay.
8. Responsible disclosure
If you find a security vulnerability, please email security@selrgroup.com.au with details and a clear reproduction. Please do not publicly disclose until we've had a chance to fix.
Our commitments to good-faith reporters:
- Acknowledgement within 48 hours.
- Resolution status update within 7 days, weekly thereafter until fixed.
- Public credit (your call) on a security acknowledgements page once fixed.
- Reward bounties for impactful findings, paid via Stripe. Bounty tiers scale with severity - emailed on report.
Out of scope: rate-limit bypass on low-cost endpoints, denial-of-service attacks, social engineering of staff, physical access attempts, third-party processor vulnerabilities (report those upstream).
9. What we're working on next
Tracked publicly. Currently in flight:
- SOC 2 Type I audit - planned for Phase 2.
- Independent penetration test on the runtime - planned for Phase 2.
- Public bug-bounty program graduating from invite-only to open - Phase 2.
- ISO 27001 readiness assessment - exploratory, depends on enterprise demand.
Have questions about this policy?
Get in touch - we'd rather give you a straight answer than make you read between the lines.