Skip to content

AccessPolicy validation checks maxLength=512 before percent-encoding, causing 500 Internal when OpenFGA TupleKey.User exceeds 512 bytes #3291

Open

Description

Summary & Root Cause

The 512-byte limit is enforced on the raw member string. OpenFGA's TupleKey.User limit (also 512) applies to the encoded string that formatUser produces. Each :, %, #, space or * in the ID grows by 2 bytes when encoded. A member like "user:" + "a:"*180 is 365 bytes raw (passes) and encodes to 5 + 180*4 = 725 bytes. OpenFGA rejects it inside the policy write transaction with InvalidArgument. That status is not an apierror, so mapAccessPolicyWrite wraps it as a plain error and the client sees codes.Internal with OpenFGA's validation text.

Affected Code Locations

  • cmd/ateapi/internal/apivalidation/zz_generated.validation.go:1697-1702: Validate_Binding applies validate.MaxLength(..., 512) to each raw members string.
  • cmd/ateapi/internal/apivalidation/access_policy.go:144-148: validateBindings calls authz.FormatMember(member) but only checks the error. It never checks the length of the encoded result.
  • cmd/ateapi/internal/authz/authz_util.go:101-107: tupleReplacer expands %→%25, :→%3A, #→%23, space→%20, *→%2A (1 byte to 3 bytes each).
  • cmd/ateapi/internal/authz/authz_util.go:157-159: formatUser returns "user:" + tupleReplacer.Replace(id).
  • cmd/ateapi/internal/authz/authz_util.go:164-176: FormatMember validates prefix, empty, wildcard and control characters. It has no length check.
  • cmd/ateapi/internal/authz/policy_manager.go:176: wraps the OpenFGA error as reconciling policy tuples on %q: %w.
  • cmd/ateapi/internal/controlapi/access_policy.go:171-188: mapAccessPolicyWrite falls through to fmt.Errorf("while writing AccessPolicy: %w", err). A plain error reaches the caller as codes.Internal.

Note: Earlier write-ups cited the generated validator as api/ateapi/v1/zz_generated.validation.go. At 15b58199 that path does not exist. The file is cmd/ateapi/internal/apivalidation/zz_generated.validation.go, and lines 1697-1702 there are the MaxLength(512) check.

Detailed Reproduction Guide

  1. As an atespace owner, fetch the current policy and add one viewer member whose raw length is 512 bytes or less but which contains many : characters:
kubectl ate --token-file alice.token get access-policy -a ate-demo-counter -o json > pol-current.json
LONG_COLONS="user:$(printf 'a:%.0s' $(seq 1 180))"   # 365 bytes raw, 725 bytes encoded
jq --arg m "$LONG_COLONS" '(.bindings[] | select(.role == "viewer")).members += [$m]' pol-current.json > pol-512-overflow.json
kubectl ate --token-file alice.token update access-policy -a ate-demo-counter -f pol-512-overflow.json

Expected vs. Actual Behavior

  • Expected: 400 InvalidArgument on access_policy.bindings[i].members[j], saying the encoded member exceeds 512 bytes. No OpenFGA call is made.
  • Actual: the request passes validation and fails in fgaServer.Write with 500 codes.Internal, which leaks the OpenFGA validation chain.

Observed Output & Logs

$ kubectl ate --token-file alice.token update access-policy -a ate-demo-counter -f pol-512-overflow.json
Error: failed to update atespace "ate-demo-counter" access policy: rpc error: code = Internal desc = internal server error: while writing AccessPolicy: reconciling access policy bindings for ate-demo-counter: reconciling policy tuples on "atespace:ate-demo-counter": rpc error: code = InvalidArgument desc = invalid WriteRequest.Writes: embedded message failed validation | caused by: invalid WriteRequestWrites.TupleKeys[0]: embedded message failed validation | caused by: invalid TupleKey.User: value length must be at most 512 bytes
RC=1
ate-demo-counter policy uid=11a20139-db83-43e7-bba0-f53981455032 version=1
$ kubectl ate --token-file alice.token update access-policy -a ate-demo-counter -f pol-512-overflow.json
Error: failed to update atespace "ate-demo-counter" access policy: rpc error: code = Internal desc = internal server error: while writing AccessPolicy: reconciling access policy bindings for ate-demo-counter: reconciling policy tuples on "atespace:ate-demo-counter": rpc error: code = InvalidArgument desc = invalid WriteRequest.Writes: embedded message failed validation | caused by: invalid WriteRequestWrites.TupleKeys[0]: embedded message failed validation | caused by: invalid TupleKey.User: value length must be at most 512 bytes
RC=1
policy version after failed update: 1 (unchanged => tx rolled back)

Activity

  1. added 2 commits that reference this issue on Oct 27, 2026
    bf2ff34
    caf4674
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions