Security Cheatsheet

Quick, practical defaults for secure apps.

Properties and Hooks

  • Return None from a property hook to hide/deny: - GET → hide property in UI and API - PUT/POST → make property read-only/immutable

  • Store sensitive data in Attributes (buckets), not regular properties.

Access Control

  • Prefer built-in trust types: viewer, friend, partner, admin, mcp_client.

  • Add custom trust types only when necessary; use pattern-based permissions.

  • Precedence: Explicit deny > explicit allow > trust type allow > default deny.

  • Permission merging: Individual overrides UNION with base patterns (fail-safe).

  • To restrict access, use excluded_patterns; base patterns cannot be narrowed.

  • Use merge_base=False only when explicit full override is needed.

OAuth2

  • Always validate provider config; use the provider-agnostic factory.

  • Google: refresh tokens available; GitHub: no refresh tokens.

  • GitHub: only verified primary emails are accepted for actor linking. Unverified primary emails are skipped to prevent account-linking attacks via the GitHub /user/emails API.

  • Expect 401 at protected endpoints with a proper WWW-Authenticate header.

  • When multiple providers are configured, 401 redirects go to the factory login page (not directly to a provider) to let the user choose.

Custom Routes

  • For custom routes, use auth.check_and_verify_auth() instead of ad-hoc authentication.

  • Always validate the actor_id parameter matches the authenticated user.

  • Handle OAuth2 redirects properly (302 responses with Location header).

Web UI

  • Enable UI only when needed; it enforces OAuth2 when configured.

  • Never use relative links in templates; use actor_root and actor_www.

Data Backend

  • Local dev: use DynamoDB Local with AWS_DB_HOST set.

  • Production: use IAM with least privilege and do not set AWS_DB_HOST.