focusreactive / focusreactive/payload-plugins
translator: translated writes bypass collection access control
- Dominant language
- TypeScript
- Stars
- 19
- Forks
- 0
- Avg merge
- 16h 54m
- Merged PRs (30d)
- 19
Description
Read against **0.11.0**. Split out of #102, where it is named as "a separate, smaller improvement".
## Problem
`saveTranslatedDocument` calls `payload.update(...)` with no `user` and no `overrideAccess: false`
(`src/server/features/translate-document/handler.ts`). The Local API defaults to
`overrideAccess: true`, so collection access control never runs on a translated write.
Measured on Payload 3.84.1: a collection declared `access: { update: () => false }` — a blanket deny —
still accepted the translated value into the target locale. Nothing about the write is checked.
## Why this matters
The plugin's own endpoint guard (`access?: AccessGuard`) controls who may *trigger* a translation, and
it defaults to `undefined` — no restriction. So on a default install the two layers that could stop an
unauthorized write are both absent: the endpoint is open and the write bypasses collection access.
For a host that models editorial permissions per collection, translation is a hole straight through
them.
## Why it is not a one-line fix
Passing `overrideAccess: false` alone would deny *every* translation, because there is no user to check
against. Nothing threads one: every handler receives `req.payload` rather than `req`, and
`TranslateDocumentHandler.handle(payload, input)` takes a bare `Payload`. Background jobs make it
harder still — a job runs with no authenticated user by construction, so even a fully threaded request
has nobody to authorize on the async path.
So a real fix has to decide what a background translation runs *as*.
## Suggested shape
Two parts, roughly independent:
1. **Thread the request.** Pass `req` (or a `user`) from the endpoint down to the write, so a
synchronously-run translation is authorized as the caller. Payload's update accepts
`req?: Partial` for exactly this, and it threads the transaction too.
2. **Decide the background identity.** Give the plugin config a way to name the user a queued
translation acts as — a fixed service user, or the user who enqueued it, captured at enqueue time
and replayed on the job.
Whatever the shape, the default cannot silently start denying writes on existing installs.
## Related
- #102 — the draft/publish half of the same write, being fixed separately.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in src/server/features/translate-document/handler.ts and trace TranslateDocumentHandler.handle(payload, input) through both endpoint and queued translation paths. Determine how request or user identity reaches the translated write, then verify collection access is enforced without silently denying existing installations or leaving background jobs undefined.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- authorization, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100