# API security

Run Glyphfield's public generation API safely with its input limits, remote URL rule, CORS headers and production rate limit, and verify each control.

`POST /api/generate` is public and unauthenticated by design. The application code validates every request, and the hosting edge limits request volume. A deployment needs both controls.

## Risks and controls [#risks-and-controls]

| Risk                           | Application control                                                                                                                                                              | Deployment control                                                              |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| Oversized work                 | Request bodies are limited to 5,250,000 bytes and each image data URL to 5,000,000 characters. Background width and height run from 64 to 4096 px with at most 12,000,000 pixels | Proxy body limits should fail clearly before excessive serverless work          |
| Unexpected request fields      | Unknown top-level fields fail with `400 unknown_field`                                                                                                                           | Log repeated invalid traffic without storing submitted assets                   |
| Remote file access             | Custom images must be base64 data URLs (GIF, JPEG, PNG, SVG or WebP). Remote URLs are not fetched                                                                                | An egress policy can add a second boundary where the host supports one          |
| Repeated generation            | Validation rejects bad requests before rendering                                                                                                                                 | A rate limit per IP address on `POST /api/generate` before serverless execution |
| Exposure of browser-local data | The HTTP routes do not read Studio localStorage or IndexedDB                                                                                                                     | Serve the app from trusted HTTPS origins and control third-party scripts        |
| Stale or shared responses      | Generation responses send `Cache-Control: no-store`                                                                                                                              | Do not override that header with CDN caching                                    |

## Application validation [#application-validation]

The generation route checks the request shape, size and generator limits:

* The request needs `Content-Type: application/json`, or it fails with `415 unsupported_media_type`.
* A body over 5,250,000 bytes fails with `413 request_too_large`. The route checks the declared `Content-Length` first and the received body second.
* Background width and height must be integers from 64 to 4096, and their product cannot exceed 12,000,000 pixels.
* Remote URLs are not supported.
* Unknown top-level fields are rejected.
* Malformed or invalid requests return structured errors and do not change any browser project.
* The route processes submitted identity and asset data in memory and does not store it.

`POST /api/brand/validate` and `POST /api/brand/kit` apply the same media type and size rules. Read `GET /api/generate` and `/openapi.json` before sending a request. Do not relax a validator to make an outdated client work.

## CORS [#cors]

The agent routes send `Access-Control-Allow-Origin: *`, `Access-Control-Allow-Methods: GET, POST, OPTIONS` and `Access-Control-Allow-Headers: Content-Type, Accept`. These headers let pages on other origins call the public contract. They do not authenticate the caller, so do not treat any request as trusted.

If a private deployment needs authentication, add it as a deliberate change to the deployment and the application, and update:

1. The OPTIONS behavior and the allowed headers.
2. The security schemes in OpenAPI.
3. The `/api/agent` policies and examples.
4. The browser and server clients.
5. The error handling and the documentation.

Do not add a cookie requirement to the public examples.

## Production rate limit [#production-rate-limit]

The repository does not rate-limit requests itself. `/openapi.json` documents `429` for `POST /api/generate` as the production rate limit. The production deployment for glyphfield.com is expected to have an edge firewall rule that matches only `POST /api/generate`, counts requests per IP address in a fixed 60-second window, allows 10 requests, returns `429` after that and keeps the client limited for one minute.

The firewall rule is stored in the Vercel project, outside the repository. An administrator checks it with the Vercel CLI:

```bash
vercel firewall overview --project glyphfield --scope general-translation --json
vercel firewall rules list --project glyphfield --scope general-translation --json
vercel firewall diff --project glyphfield --scope general-translation --json
```

If the rule is missing, create it and review the diff before publishing:

```bash
vercel firewall rules add "Rate limit Glyphfield generation" \
  --description "Bound unauthenticated generation before serverless execution." \
  --condition '{"type":"path","op":"eq","value":"/api/generate"}' \
  --condition '{"type":"method","op":"eq","value":"POST"}' \
  --action rate_limit \
  --rate-limit-algo fixed_window \
  --rate-limit-keys ip \
  --rate-limit-requests 10 \
  --rate-limit-window 60 \
  --rate-limit-action rate_limit \
  --duration 1m \
  --yes \
  --project glyphfield \
  --scope general-translation
```

Publishing changes live infrastructure, so only an authorized administrator should do it. Afterward, confirm that the eleventh request from one client inside the window receives `429` and that requests succeed again after the window ends.

Other hosts need an equivalent limit that fits their traffic. The commands above apply only to Vercel.

## Browser API boundary [#browser-api-boundary]

The Browser API (`window.glyphfield.studio`) operates the active project in the visitor's browser. It reads and applies source, operates controls, accepts local files as authorized `File` objects and returns downloadable artifacts.

* Do not inject untrusted scripts into the Studio origin.
* Do not pass file path strings to file controls.
* Do not write to localStorage, IndexedDB or React internals directly.
* Share a returned Blob or copied source only with its authorized destination.
* Treat imported SVG, font, image, audio and Lottie files as user-supplied data.

The HTTP API has no access to this browser-local state.

## Logging and privacy [#logging-and-privacy]

Operational logs should record the route, status, duration and request kind. They should not store complete identities, embedded data URLs or generated artifact bodies. Redact authorization headers if a private deployment adds them.

A useful failure report contains:

* The request kind and the response error code.
* The dimensions and the approximate body size.
* The deployed commit or version and the route.
* Whether the failure happened during validation or during generation.

Do not paste proprietary source or binary data into a public issue.

## Security checks [#security-checks]

Before a release:

1. Confirm that valid discovery and generation requests succeed.
2. Confirm that malformed JSON returns `400`.
3. Confirm that a wrong content type returns `415`.
4. Confirm that an oversized body returns `413`.
5. Confirm that unknown fields and remote URLs are rejected.
6. Confirm that generation responses still send `no-store`.
7. Confirm that the edge rate limit is active in production.
8. Confirm that no HTTP route returns browser-local projects.

[Errors and limits](/docs/agents/errors), [Endpoint reference](/docs/reference/endpoints) and [Self-hosting](/docs/reference/self-hosting) cover the error codes and deployment.
