Skip to content

Harden grant(): validate actions, and guard grants on the _grant/_config system types #116

Description

@cuibonobo

Two grant() input-hygiene gaps. grant() is owner-only, so neither is an external hole — both are silent-misfire / foot-gun territory.

F4 — grant actions are validated as bare strings

_grant@1's schema is actions: array of string (stack.ts:1566-1570); grant() (stack.ts:1475-1490) writes them without checking against the GrantAction union (types.ts:215-222). A typo'd action ('read_any', 'read-all') or a malformed typeId is stored silently and simply never matches at check time (hasGrant compares against the requested action) — a permission that looks granted but isn't, with no error at grant time or use time.

Fix: validate each action in grant() against the GrantAction set and throw StackValidationError on an unknown one. (The schema language has no enum field-kind; explicit validation in grant() is the cheap fix now. An enum scalar kind is a possible future addition, out of scope.) Optionally validate the typeId is a well-formed versioned/base id.

F5 — grants on system types are a privilege-escalation foot-gun

A create or update-any grant on _grant@1 lets the grantee mint their own grants; a default (any-authenticated) grant on it is self-service escalation for anyone. Same shape for _config@1. Only the owner can call grant(), so this is owner-error, not an external attack — but grant() can cheaply refuse it, matching the "privilege-bearing verbs stay owner-only" principle (#67).

Decided: refuse grants on the _grant and _config families outright (throw StackValidationError). No override flag — there's no legitimate reason to delegate grant-creation or config access at this scale. The refusal is narrow: _grant and _config only. Other reserved types stay grantable — _attachment create grants are load-bearing (every uploader needs one), and _entity/_group create grants are plausibly legitimate.

Work items

  • grant(): validate actions against GrantAction; throw StackValidationError on unknown
  • grant(): refuse _grant/_config target types (throw StackValidationError)
  • Tests: unknown action rejected; grant on _grant@1/_config@1 rejected; grant on _attachment@1 still allowed

Refs

#57 (grant model), #58 (group roles), #67 (_config protection / privilege-bearing-verbs-owner-only). From docs/design-assessment-2026-07.md §F4/§F5.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions