Skip to content

Couple jwt_linked to require_link, or retire the mode value that decides nothing #1433

Description

@OchnikBartek

Severity: Low · AUD-CHAN-12

What's wrong

The access mode jwt_linked enforces nothing on its own: with require_link=False (the default) it is behaviourally identical to open. An operator who selects "jwt_linked" — reasonably read as "an account is required" — gets no added gating unless they also flip a second, independent switch.

Where

  • backend/app/schemas/channel_bot.py:19,22mode and require_link are independent fields with no validator coupling them
  • backend/app/services/channels/router.py:773-792_check_access enforces only whitelist/group_only; jwt_linked passes through (:792)
  • backend/app/services/channels/router.py:972 — linking is enforced only when policy.get("require_link", False) is truthy
  • backend/app/services/channels/router.py:813-815_admits_unlinked keys off require_link, not mode
  • backend/app/services/channels/base.py:32"require_link": False in DEFAULT_ACCESS_POLICY

How it fails

mode="jwt_linked", require_link=False admits an unlinked room sender under the binding creator exactly as open does. This is adjacent to a deliberate decision: #639 intentionally made require_link the switch and admitted unlinked room senders under the binding. The residual is that the jwt_linked mode value now decides nothing — a gate that reads as applied but is inert (the #718 class), though not an escalation (unlinked never runs role-less or as another user).

Fix

Either a schema validator forcing require_link=True when mode="jwt_linked", or make _check_access/_admits_unlinked treat the mode itself as requiring a link — or retire the mode value and let require_link be the only knob, updating the dashboard/CLI copy.

Acceptance criteria

  • A bot saved as jwt_linked refuses an unlinked room sender without a second setting, or the mode value is gone
  • Test: test_jwt_linked_mode_requires_a_link_even_without_require_link

Cluster Channels and bots in #168. Nearest: #639 (made require_link the switch), #718 (the inert-gate class). Pre-existing, found in the 2026-09-03 channels audit.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

audit-2026-09-03Found in the 2026-09-03 channels auditbugSomething isn't workingeffort:sUnder a dayseverity:lowClean-up, dead code, minor duplication

Type

Projects

  • Status
    Done

Relationships

None yet

Development

No branches or pull requests

Issue actions