Documentation · Security
Security model.
Core principles
- Credentials stay local. Your API keys never pass through LoopSkill servers. Skills hit third-party APIs directly with your env vars.
- Skills run locally. LoopSkill only serves text files. Your agent decides what to execute.
- Plain-text transparency. No obfuscated code, no hidden payloads. Inspect every line before running — it's just Markdown.
- Checked tarballs. A publisher signs the tarball's sha256 with an
ed25519 key and the API verifies that signature at upload, before storing anything.
At install, the API returns the stored tarball's
checksum_sha256and an expiring download URL; compare the checksum with the hash of the bytes you downloaded before extracting. The signature itself is not served to installers. - Architecture-aware install. The runtime probe refuses to install on incompatible hardware (wrong OS, insufficient VRAM, missing CUDA) and suggests an alternative from the graph.
Authentication model
All API requests authenticate via the x-api-key header. Four key prefixes
map to four auth scopes:
| Prefix | Scope | Issued by |
|---|---|---|
rec_ | Standard API key — catalog access + installs up to your tier limit | Dashboard → API Keys |
cbt_ | Bundle-scoped token — read, install (default), or edit access to one specific bundle. See share tokens. | loopskill_share_create MCP tool, or Client delivery tab in /library |
rec_fleet_ | Fleet key — bundle-scoped, multi-agent, Pro tier required | Dashboard → Fleet → New fleet key |
| Bearer JWT | Browser session — dashboard + OAuth flows only, not for agent use | GitHub OAuth callback |
The APIKeyMiddleware validates every request before it reaches a route
handler. Invalid keys return 401. Tier-gated resources return
403 with a upgrade_url field in the response body.
Tier gating
Skills are gated by tier. The tier hierarchy (lowest to highest) is:
- free — available to all API key holders, including free-tier accounts
- pro — requires Pro subscription ($9.95/mo)
- pro_plus — requires Pro subscription; advanced fleet and deployment features
The GET /api/skills/access endpoint provides a pre-flight check: pass a
slug and your key and it returns {"access": true} or
{"access": false, "reason": "tier_required", "required_tier": "pro"}.
The meta-skill calls this before attempting an install.
Publish-time signature & install-time checksum
Two different checks happen at two different moments. Only the first involves a signature:
- At publish: the upload carries an ed25519 public key and a signature
over the sha256 of the tarball. The API verifies it
(
app/publisher_routes.py) and rejects the upload on a mismatch. - At install:
GET /api/skills/installreturns an expiring signed download URL (an HMAC-signed link, not a signature on the file) andchecksum_sha256for the stored tarball. The installer compares that checksum with the sha256 of the bytes it downloaded and aborts on a mismatch. No ed25519 signature or public key is served to installers, and installers do not verify one.
Versions are content-addressed (sha256) and pinned by version number, so a published tarball cannot be swapped for another without the checksum changing.
Publish-time review pipeline
Every skill passes through the following gates before appearing in the catalog:
- Discipline linter (A.7): blocks user-name leaks,
curl | bashpatterns, hardcoded$HOMEpaths, internal-infra references, and unallowlisted external promo links. - Tarball scan: checks for binary executables, symlink attacks, and
path traversal (
../in filenames). Rejects any tarball that fails. - Manual review: every skill is read, tested, and approved by a human reviewer before it lands in the catalog. We are the publisher.
- Signature check & checksum: the upload's ed25519 signature is verified before the tarball is stored, and its sha256 is recorded. Patching a skill requires a full re-publish, which produces a new version and a new checksum.
Community-submitted skills (via loopskill_publish_request MCP tool) follow
the same pipeline plus a GitHub issue review step. See Publishing.
Optional sandbox (declared per-skill)
Skills can declare a [sandbox] block in their skill.toml
with a network allowlist, filesystem write paths, and an allowed executable list.
When enforced, the sandbox runner uses
bubblewrap or
firejail (publisher's choice) to isolate
the skill's setup and runtime. The host must have at least one sandbox backend available —
the runtime check happens at install time, not at run time.
What LoopSkill never does
- Never executes code. We serve text files. Your agent decides what to run.
- Never has remote access to your machine.
- Never proxies your third-party API calls.
- Never serves obfuscated content.
- Never logs your inputs, outputs, or credentials.
Telemetry & privacy
Anonymous aggregates only by default: install/use/result events with hashed agent class, hashed user ID, duration in seconds, retry count. No payload contents, no credential fingerprints, no inputs or outputs. Pro subscribers can opt into pseudonymous payload sampling to improve their own skills — this requires explicit opt-in per bundle.
To opt out entirely (RECIPES_TELEMETRY is a legacy variable name, still canonical — the code only reads this exact name today):
export RECIPES_TELEMETRY=off Reporting a vulnerability
Email security@loopskill.io with the skill slug, version, and reproduction steps. We triage all security reports. Critical vulns get a hotfix and the skill is taken offline pending review.