Skip to main content

Security Best Practices

Appilots gives an AI agent the ability to act inside your app. That power is governed by three layers you control: who holds a valid key, what the agent is permitted to do, and which actions require a human to confirm. Get all three right and a compromised or confused agent session has very little blast radius.

1. Treat API keys as revocable, scoped capabilities​

A mobile app's API key ships inside the app binary, and app binaries can be unpacked. Assume the key is semi-public once shipped — your protection comes from scoping and revocability, not from secrecy of the key itself:

  • Scope: each key is bound to exactly one project. Use separate projects (or at minimum separate keys) per environment so staging and production never share a credential — see Projects & API keys.
  • Revocability: if a key is abused or leaked, revoke it in the dashboard and issue a new one. Plan for this: one key per distribution channel means revocation doesn't take down every build at once.
  • Rotation: rotate keys periodically as hygiene, and immediately after any suspected exposure.
  • Keep keys out of source control: .appilotsrc holds the key in plain text — appilots init adds it to .gitignore, but verify before your first commit (CLI configuration). In CI, use the APPILOTS_API_KEY secret env var and no config file at all (CI integration).
  • Don't hardcode keys in app source either — inject them at build time (the Metro plugin + .appilotsrc flow does this) so the key never appears in your repository history.

2. Grant the minimum permissions the integration needs​

The AgentPermissions model defaults to fully open when unset. For production, set it deliberately:

  • Turn off capabilities you don't use — a support-navigation assistant that never fills forms should run with canFillForms: false and canSubmitForms: false.
  • Use blockedScreens for areas the agent has no business in (admin panels, payment settings), or allowedScreens to whitelist when the surface is small.
  • Use allowedActions to restrict the action types available at all.
  • Set the project-wide baseline in the dashboard and tighten per-build with SDK-side permissions where a specific app variant warrants less.

3. Put risk metadata on every mutating action​

Confirmation gating is only as good as your metadata. Any action that changes state — saves, payments, deletions, subscription changes — should declare what it does:

actions: [
{
id: 'deleteOrder',
label: 'Delete order',
type: 'button',
effect: 'destructive',
riskLevel: 'high',
destructive: true,
},
];
  • effect: 'write' | 'destructive' + riskLevel let the platform gate the action without guessing from button labels — critical in multilingual apps (Agent actions).
  • Destructive/high-risk actions get an explicit confirmation card the user must tap — and confirm steps can never be auto-executed.
  • Enforce coverage mechanically: appilots sync --strict-metadata fails the build when a mutating action is missing this metadata (Metadata quality). Make it a required CI check.

4. Authorize external integration calls per user​

If the project has integrations, the agent can call your other systems. Those calls are denied unless your backend grants each exact call to the signed-in user:

  • Issue grants only after checking the user's own permissions, and only for responses the user may see in full.
  • Use stable, non-reusable user ids, and never take ids or grants from client input.
  • Keep the publish key that issues tokens on your server. Put secrets in the integration's token field, not in its headers, which project members can read.
  • Protect non-repeatable writes with idempotency: a grant can be reused until the token expires.

5. Operational hygiene​

  • Least-privilege team roles: default new teammates to member or viewer; reserve admin/owner for people who manage keys, webhooks, and billing (Team management).
  • Verify webhook signatures: every webhook delivery is HMAC-signed — reject any delivery whose signature doesn't validate against your stored secret (Webhooks). Webhook secrets are shown once, like API keys; store them accordingly.
  • Set a budget so abuse or a bug surfaces as a capped bill, not an open-ended one (Permissions, budget & personalization).
  • Watch the dashboards: unusual usage patterns in usage & analytics are your early signal that a key is being used outside its intended app.
  • Mind end-user data: the identify surface is write-only from the app and identifiers are never sent to the model — but only send the identifiers your support workflow actually needs.

Quick checklist​

  • Separate key per environment and distribution channel
  • No keys in git history; .appilotsrc ignored; CI uses secret env vars
  • Rotation procedure documented; revocation tested
  • Permissions explicitly configured (not left at default-open)
  • Every mutating action carries effect/riskLevel; --strict-metadata enforced in CI
  • Webhook signature verification implemented
  • Team roles follow least privilege
  • Budget configured
  • Integration grants issued server-side, per user, with exact arguments