feat: enhance medialib image handling and add asset URL resolution

- Implemented `resolveApiAssetUrl` function to normalize asset URLs based on API base.
- Updated `MedialibImage` component to utilize new asset URL resolution and added support for alt text and class properties.
- Enhanced image loading behavior with improved width measurement and focal point handling.
- Added placeholder image handling and improved accessibility with alt text.
- Introduced new test script for auditing broken links in skill documentation.
- Expanded seeded test content to include medialib entries and updated related tests for pagebuilder previews.
- Improved global setup and teardown logging for clarity on seeded content management.
This commit is contained in:
2026-05-17 00:52:41 +00:00
parent 958b45272d
commit 4020ad62c5
44 changed files with 4276 additions and 867 deletions
@@ -1,6 +1,6 @@
---
name: security-hardening-and-token-strategy
description: Apply current tibi-server security practices to website projects. Covers secret handling, token strategies, bulk-permission safety, cookie settings, SSRF/exec risks in hooks, and secure operator decisions for this stack.
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
@@ -9,150 +9,199 @@ description: Apply current tibi-server security practices to website projects. C
Use this skill when:
- Setting up or reviewing authentication and token use on this stack
- Deciding how admin tokens, JWT auth, and token permissions should be used
- Hardening hooks, actions, and project config against obvious security mistakes
- Reviewing bulk permissions, secrets, cookie settings, or risky server-side capabilities
- 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
The goal is to keep projects on this starter aligned with the current tibi-server security model and known risk areas.
Keep projects on this starter aligned with the current tibi-server security model and with the security-sensitive operator decisions the stack exposes.
This skill is not a generic web security guide. It is about the concrete operator and implementation choices this 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-related decisions:
Use these sources when implementing or reviewing security decisions:
- `tibi-server/docs/05-authentication.md`
- `tibi-server/docs/14-security.md`
- relevant collection/action permissions in `api/`
- project environment/config files
- `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:
This stack exposes multiple auth mechanisms. Do not mix them casually.
- JWT user auth
- refresh token cookie flow
- refresh-token cookie flow
- admin tokens
- token-based permissions for API-style access
- token-based permission sets for narrower machine access
Do not mix them casually. Each one has a different operational purpose.
Recommended default:
## Recommended token strategy
- 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
Use:
## Token header distinction
- **JWT user auth** for real users in admin or authenticated workflows
- **refresh cookies** for session continuation where appropriate
- **admin tokens** only for server/admin/ops scenarios that truly need that level of access
- **token permissions** for narrow integration access or machine clients
Use the right header for the right surface:
Avoid using broad admin tokens where a narrow project or collection-level token permission is enough.
- 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`
## Secrets handling
Do not assume a working `Token` header implies system-level admin rights.
Do not keep production secrets as plain literals in committed config.
## Secret handling
Prefer environment-variable substitution for:
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
- LLM API keys
- external API tokens
- admin token values
- admin tokens
- external API keys
- LLM/embedding provider keys
If a project ships real secrets in config, treat that as a structural problem, not a cosmetic cleanup.
If secrets are hardcoded in committed config, treat that as a structural problem, not as cleanup trivia.
## Bulk permission safety
Bulk mutations are explicitly more dangerous than single-document mutations.
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`
Do not enable bulk operations casually in website projects. Most editor workflows do not need them.
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
For refresh-token flows, ensure the deployment matches secure cookie expectations.
Refresh-token flows should respect the target environment.
Important considerations:
Review:
- secure cookies should stay enabled in HTTPS environments
- local non-HTTPS development may need explicit relaxation
- do not debug production cookie issues by weakening production defaults globally
- `api.secureCookies`
- HTTPS vs local HTTP expectations
- whether debugging shortcuts are accidentally bleeding into production config
## Hook risk surfaces
Do not weaken secure-cookie behavior globally just to make a dev shortcut work.
Current tibi-server exposes powerful server-side capabilities. Some of them require explicit restraint.
## 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:
- `http.fetch` / `http.fetchStream` can create SSRF risk
- `exec.command` can create command-execution risk
- `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.
## Query-parameter token risk
When such capabilities are used, document:
Token permissions may be passed through query parameters for specific cases, but this is a documented risk surface.
Prefer header-based token transport when possible.
If query tokens are unavoidable:
- avoid logging full URLs with sensitive query strings
- understand proxy/referrer/history exposure
- scope the token as narrowly as possible
## Permission boundaries
Security on this stack is layered.
Think in terms of:
- project visibility
- collection method permissions
- field-level restrictions
- token scope
- public vs authenticated action access
Do not rely on frontend hiding or convention where server-side permissions should be explicit.
- why they are necessary
- what the allowed target surface is
- what the safer rejected alternatives were
## CORS configuration
CORS follows a 3-level hierarchy. Configure it in `api/config.yml` under `cors:` for project-wide settings, or in individual collection/action YAML for per-endpoint overrides:
CORS follows a hierarchy. Configure it deliberately instead of widening it reactively.
| Level | Configuration location | Scope |
|-------|----------------------|-------|
| Server | tibi-server `config.yml` | Global default |
| Project | `api/config.yml``cors:` | Per project |
| Collection/Action | Collection or action YAML → `cors:` | Per endpoint |
Levels:
Each level can `merge: true` (append to parent) or `merge: false` (replace entirely).
- server-level `config.yml`
- project-level `api/config.yml`
- collection/action-level YAML overrides
For a project that serves a browser-based SPA to end users on its own domain and serves API/tibiadmin on separate subdomains, the default (no explicit CORS config) is usually correct since the SPA makes same-origin API calls via the BrowserSync/production reverse proxy. Add explicit CORS only when:
- the API is called from external origins (e.g. third-party integrations)
- the admin UI is served on a different origin than the API
- an action endpoint needs to support cross-origin form submissions
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.
See `tibi-server/docs/02-configuration.md` (section "CORS Configuration Hierarchy") for details.
## Recommended implementation patterns
## Secure implementation patterns
### Public form endpoint
### Public form workflow
Recommended shape:
- public action with narrow allowed methods
- public action with narrow methods
- server-side validation
- no broad admin tokens in the browser
- no unnecessary collection write permissions exposed publicly
- no admin token in the browser
- separate internal persistence only when truly required
### Integration token
@@ -162,32 +211,42 @@ Recommended shape:
- minimal collection/action scope
- header-based transport preferred
### Hook that calls external services
### Sensitive internal fields
Recommended shape:
- fixed or validated destination URLs
- no arbitrary user-controlled internal target fetching
- minimal capability needed for the feature
- 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
- Using admin tokens for routine frontend or integration traffic
- Enabling bulk write permissions without a strong operational reason
- Treating hook `http.fetch` and `exec.command` as risk-free utilities
- Solving access control in the UI instead of on the server
- 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. Public endpoints expose only the required methods.
5. Risky hook capabilities are constrained by design.
6. `yarn validate` stays clean.
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
@@ -195,8 +254,9 @@ When asked to harden or design secure access on this starter, inspect in this or
1. `tibi-server/docs/05-authentication.md`
2. `tibi-server/docs/14-security.md`
3. the relevant collection/action permission sets
4. secret sourcing in config/env
5. whether hooks use risky capabilities like outbound fetch or exec
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.
This prevents working implementations that quietly widen the attack surface.