focusreactive / focusreactive/payload-plugins

translator: translated writes bypass collection access control

Open
#113 0 comments 0 reactions 0 assignees View on GitHub
enhancement translator
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.