--- name: security-hardening-and-token-strategy description: Apply current tibi-server security practices to website projects. Covers token strategy, secret handling, rate limiting, bulk-permission safety, cookie settings, risky hook capabilities, and secure operator decisions for this stack. --- # security-hardening-and-token-strategy ## When to use this skill Use this skill when: - setting up or reviewing authentication and token usage on this stack - deciding how admin tokens, JWT auth, and token permissions should be used - hardening hooks, actions, and project config against current upstream security risks - reviewing bulk permissions, rate limiting, cookies, secrets, or risky server-side capabilities ## Goal Keep projects on this starter aligned with the current tibi-server security model and with the security-sensitive operator decisions the stack exposes. This is not a generic web-security primer. It is the practical security workflow for this repo family. ## Source of truth Use these sources when implementing or reviewing security decisions: - `tibi-server/docs/05-authentication.md` - `tibi-server/docs/14-security.md` - `tibi-server/docs/17-field-level-permissions.md` - `tibi-server/docs/02-configuration.md` - project config and collection/action permission YAML files ## Security review order When asked to harden a project, inspect in this order: 1. secret sourcing in config/env 2. token type and scope 3. collection/action permissions 4. bulk permission exposure 5. field-level restrictions 6. rate limiting and cookie settings 7. risky hook capabilities such as outbound fetch or exec This prevents “secure enough” changes that leave the real attack surface untouched. ## Authentication surfaces This stack exposes multiple auth mechanisms. Do not mix them casually. - JWT user auth - refresh-token cookie flow - admin tokens - token-based permission sets for narrower machine access Recommended default: - use JWT user auth for real users and editor/admin sessions - use refresh cookies for session continuation where appropriate - use admin tokens only for system/admin/ops flows that truly need them - use token permissions for narrow machine integrations ## Token header distinction Use the right header for the right surface: - system-level API such as project CRUD, admin reload, shutdown: `X-Admin-Token` - collection-level CRUD via static project token: `Token` - JWT-authenticated user flow: `X-Auth-Token` Do not assume a working `Token` header implies system-level admin rights. ## Secret handling Do not keep production secrets as committed literals if the deployment can source them from env or operator-managed secrets. Review at minimum: - JWT secrets - SMTP credentials - admin tokens - external API keys - LLM/embedding provider keys If secrets are hardcoded in committed config, treat that as a structural problem, not as cleanup trivia. ## Bulk permission safety Bulk operations are more dangerous than single-document mutations. Important rule: - boolean `post: true` / `put: true` / `delete: true` does not imply bulk access - bulk requires object-form permissions with `bulk: true` Example: ```yaml permissions: user: methods: post: allow: true bulk: true ``` Do not enable bulk access casually in website projects. Most editorial workflows do not need it. ## Field-level security Security on this stack is not only collection-method based. Review all of these layers together: - collection methods - `readonlyFields` - `hiddenFields` - field-level `readonly` / `hidden` - eval-based field rules - collection visibility in the admin UI If a field should not be editable or visible, enforce that on the server. Do not rely on frontend omission. ## Rate limiting and login hardening Current upstream tibi-server supports login rate limiting with exponential backoff. Review these config points: - `ratelimit.enabled` - `ratelimit.loginInitialDelay` - `ratelimit.loginMaxDelay` - `ratelimit.loginResetAfter` Security implication: - a project may look fine in normal use while still being too soft against brute-force attempts if rate limiting is not configured as expected For serious deployments, do not leave this unreviewed just because login works. ## Cookie and session hardening Refresh-token flows should respect the target environment. Review: - `api.secureCookies` - HTTPS vs local HTTP expectations - whether debugging shortcuts are accidentally bleeding into production config Do not weaken secure-cookie behavior globally just to make a dev shortcut work. ## Query-parameter token risk Token-based permissions can be passed via query parameters in some cases, but this is a documented risk surface. If query tokens are unavoidable: - scope them narrowly - avoid logging full URLs with sensitive query strings - understand proxy, history, and referrer exposure Prefer header-based transport whenever possible. ## Risky hook capabilities Current tibi-server exposes powerful capabilities in hooks. Treat them as explicit design decisions, not utilities. Particularly important: - `context.http.fetch()` / `context.http.fetchStream()` can create SSRF risk - `context.exec.command()` can create command-execution risk - broad filesystem/network access in hooks should not be treated as harmless If a feature can be implemented without shell execution or arbitrary internal fetches, prefer the safer path. When such capabilities are used, document: - why they are necessary - what the allowed target surface is - what the safer rejected alternatives were ## CORS configuration CORS follows a hierarchy. Configure it deliberately instead of widening it reactively. Levels: - server-level `config.yml` - project-level `api/config.yml` - collection/action-level YAML overrides For typical website projects on this starter, the default proxy setup often means no aggressive cross-origin opening is required. Add explicit CORS only when the real deployment needs external origins. ## Recommended implementation patterns ### Public form workflow Recommended shape: - public action with narrow methods - server-side validation - no admin token in the browser - separate internal persistence only when truly required ### Integration token Recommended shape: - dedicated narrow token permission set - minimal collection/action scope - header-based transport preferred ### Sensitive internal fields Recommended shape: - use hidden/readonly restrictions explicitly - keep admin UI aligned with those restrictions - do not let previews depend on hidden-only data ### Hook that calls external systems Recommended shape: - fixed or validated targets - no user-controlled arbitrary internal fetches - no shell execution unless unavoidable ## Anti-patterns - hardcoded production secrets in committed config - broad admin tokens used for normal frontend or integration traffic - bulk permissions enabled without a concrete operator need - risky hook capabilities treated as harmless helpers - collection security solved in the UI instead of the server - production cookie or rate-limit settings weakened for convenience ## Verification checklist After security-relevant changes, verify all of these: 1. secrets are sourced appropriately 2. token type matches the intended actor and scope 3. bulk permissions are not broader than necessary 4. readonly/hidden behavior is correct on the API 5. rate limiting and cookie settings match the environment 6. risky hook capabilities are constrained by design 7. `yarn validate` stays clean ## What an LLM should inspect first When asked to harden or design secure access on this starter, inspect in this order: 1. `tibi-server/docs/05-authentication.md` 2. `tibi-server/docs/14-security.md` 3. `tibi-server/docs/17-field-level-permissions.md` 4. the relevant collection/action permission sets 5. secret sourcing in config/env 6. whether hooks use risky capabilities like outbound fetch or exec This prevents working implementations that quietly widen the attack surface.