Redact channel config secrets in API responses — readable by any authenticated user today #47

Closed
opened 2026-07-18 05:31:14 +00:00 by claude-bot · 1 comment
Contributor

ChannelRead (app/schemas/channel.py:23-32) serializes config verbatim.
GET /api/channels/ and /api/channels/{id} (app/api/channels.py:62-109)
require only require_user, and can_view_channel
(app/api/permissions.py:68-73) grants view on global channels to every role
including readonly. Config JSONB contains live secrets (Webex bot_token,
Pushover app_token/user_key, webhook Authorization headers). Net: any
authenticated user can read shared-channel credentials.

Fix: redact known secret keys per channel type in read responses (mirror the
AI provider has_api_key pattern, app/api/ai.py); return full config only to
can_manage_channel callers where the edit UI needs it — or never, with
write-only semantics and empty-means-unchanged updates. Rotate exposed tokens
if other users have had accounts.

Acceptance criteria:

  • List/read responses contain no token/header secret values for non-managers
  • Edit flow still works (write-only or manager-scoped full read)
  • Test: readonly user fetching a global channel sees redacted config

Filed from the 2026-07-17 codebase audit (docs/.internal/report-2026-07-17.md), finding F-08.

`ChannelRead` (app/schemas/channel.py:23-32) serializes `config` verbatim. `GET /api/channels/` and `/api/channels/{id}` (app/api/channels.py:62-109) require only `require_user`, and `can_view_channel` (app/api/permissions.py:68-73) grants view on global channels to every role including readonly. Config JSONB contains live secrets (Webex bot_token, Pushover app_token/user_key, webhook Authorization headers). Net: any authenticated user can read shared-channel credentials. Fix: redact known secret keys per channel type in read responses (mirror the AI provider `has_api_key` pattern, app/api/ai.py); return full config only to `can_manage_channel` callers where the edit UI needs it — or never, with write-only semantics and empty-means-unchanged updates. Rotate exposed tokens if other users have had accounts. **Acceptance criteria:** - [ ] List/read responses contain no token/header secret values for non-managers - [ ] Edit flow still works (write-only or manager-scoped full read) - [ ] Test: readonly user fetching a global channel sees redacted config --- _Filed from the 2026-07-17 codebase audit (`docs/.internal/report-2026-07-17.md`), finding F-08._
Author
Contributor

Fixed in #93 (merged to main). Secret-bearing config keys are now redacted to has_<key> indicators in list responses and for non-managers on the single GET; full config is returned only to callers who pass can_manage_channel, preserving the edit flow. Per-type secret map: webhook headers+url (a webhook URL can embed a token), webex bot_token, pushover user_key/app_token, sms to_number/from_number, signal recipients (phone numbers are treated as PII); discord/matrix keep no secrets in config. Regression tests cover readonly/non-manager redaction, list redaction for all roles, and manager full-read.

Fixed in #93 (merged to `main`). Secret-bearing config keys are now redacted to `has_<key>` indicators in list responses and for non-managers on the single GET; full config is returned only to callers who pass `can_manage_channel`, preserving the edit flow. Per-type secret map: webhook `headers`+`url` (a webhook URL can embed a token), webex `bot_token`, pushover `user_key`/`app_token`, sms `to_number`/`from_number`, signal `recipients` (phone numbers are treated as PII); discord/matrix keep no secrets in config. Regression tests cover readonly/non-manager redaction, list redaction for all roles, and manager full-read.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/WeatherBot#47
No description provided.