Guide: MSP_ADMIN can read Architect + Claude tabs (should be BCOS_ADMIN only) #16

Closed
opened 2026-07-14 17:47:47 -04:00 by hiveiq · 0 comments
Owner

Summary

On the Guide (bcos.dev only — not deployed to production), a user with role MSP_ADMIN receives the full body of every Architect and Claude tab. These tabs contain internal architecture: source file paths, DB table names, service ports, NGINX routes, and internal call flows. They are intended for BCOS staff only.

Reproduction (live, bcos.dev)

Login as msp_a@msp1.bcos.dev (role MSP_ADMIN), then:

GET https://api.bcos.dev/guide/api/v1/guide/nav
  -> 81 tabs audience=dev tab=Architect
  -> 81 tabs audience=dev tab=Claude

GET https://api.bcos.dev/guide/api/v1/guide/modules/analytics.adoons
  -> tabs: [Customer, Internal, Architect, Testing, Claude]
  -> Architect body: 4672 chars (internal architecture)
  -> Claude    body: 3918 chars (ports, tables, endpoint/auth table)

Bodies are served, not just listed in nav — this is a content leak, not a UI-hiding issue.

Root cause

MarkdownGuideService.visible() (backend/src/main/java/com/hiveops/guide/service/MarkdownGuideService.java:105-113):

case "bcos"            -> includeBcos;      // BCOS_ADMIN only
case "internal", "dev" -> includeInternal;  // MSP_ADMIN *or* BCOS_ADMIN  <-- hole
default                -> true;             // customer

Every Architect and Claude doc is tagged audience: dev. The tier name reads like "developers only", but dev is gated identically to internal, which resolves to ROLE_MSP_ADMIN || ROLE_BCOS_ADMIN (GuideController.isInternal()). Only the bcos tier is genuinely BCOS-only. The documented ladder (customer < internal < dev < bcos) is not the ladder the code implements.

Fix

Retag the 162 Architect/Claude docs from audience: dev to audience: bcos, which routes them through includeBcos (BCOS_ADMIN only). No code change, no blast radius on other tiers.

Verified: all 162 Architect/Claude docs are currently audience: dev — none are tagged otherwise, so the retag is complete by construction.

Deliberately NOT changing the dev tier mapping in code. dev also tags 35 Overview and 15 Internal docs; remapping the tier would strip those from MSP_ADMIN too, and agent.* modules (tabs: Internal/Architect/Claude only) would end up with zero visible tabs and disappear from MSP's nav entirely.

Out of scope (per Johannes): the 66 Testing tabs are also audience: dev and stay MSP_ADMIN-visible.

Impact / urgency

Guide is bcos.dev only; it is not routed in production (api.bcos.cloud/guide/* hits the nginx catch-all). So there is no live customer-facing exposure today. This must be fixed before the Guide is ever deployed to prod.

Follow-up (separate issue)

The dev tier is a footgun: it is named for developers but gates at MSP_ADMIN. Any future doc tagged audience: dev will silently be MSP-visible. Consider renaming the tier or adding a startup assertion.

## Summary On the Guide (bcos.dev only — **not** deployed to production), a user with role `MSP_ADMIN` receives the full body of every **Architect** and **Claude** tab. These tabs contain internal architecture: source file paths, DB table names, service ports, NGINX routes, and internal call flows. They are intended for BCOS staff only. ## Reproduction (live, bcos.dev) Login as `msp_a@msp1.bcos.dev` (role `MSP_ADMIN`), then: ``` GET https://api.bcos.dev/guide/api/v1/guide/nav -> 81 tabs audience=dev tab=Architect -> 81 tabs audience=dev tab=Claude GET https://api.bcos.dev/guide/api/v1/guide/modules/analytics.adoons -> tabs: [Customer, Internal, Architect, Testing, Claude] -> Architect body: 4672 chars (internal architecture) -> Claude body: 3918 chars (ports, tables, endpoint/auth table) ``` Bodies are served, not just listed in nav — this is a content leak, not a UI-hiding issue. ## Root cause `MarkdownGuideService.visible()` (backend/src/main/java/com/hiveops/guide/service/MarkdownGuideService.java:105-113): ```java case "bcos" -> includeBcos; // BCOS_ADMIN only case "internal", "dev" -> includeInternal; // MSP_ADMIN *or* BCOS_ADMIN <-- hole default -> true; // customer ``` Every Architect and Claude doc is tagged `audience: dev`. The tier name reads like "developers only", but `dev` is gated identically to `internal`, which resolves to `ROLE_MSP_ADMIN || ROLE_BCOS_ADMIN` (`GuideController.isInternal()`). Only the `bcos` tier is genuinely BCOS-only. The documented ladder (`customer < internal < dev < bcos`) is not the ladder the code implements. ## Fix Retag the 162 Architect/Claude docs from `audience: dev` to `audience: bcos`, which routes them through `includeBcos` (BCOS_ADMIN only). No code change, no blast radius on other tiers. Verified: all 162 Architect/Claude docs are currently `audience: dev` — none are tagged otherwise, so the retag is complete by construction. **Deliberately NOT changing** the `dev` tier mapping in code. `dev` also tags 35 Overview and 15 Internal docs; remapping the tier would strip those from MSP_ADMIN too, and `agent.*` modules (tabs: Internal/Architect/Claude only) would end up with zero visible tabs and disappear from MSP's nav entirely. **Out of scope (per Johannes):** the 66 `Testing` tabs are also `audience: dev` and stay MSP_ADMIN-visible. ## Impact / urgency Guide is **bcos.dev only**; it is not routed in production (`api.bcos.cloud/guide/*` hits the nginx catch-all). So there is no live customer-facing exposure today. This must be fixed **before** the Guide is ever deployed to prod. ## Follow-up (separate issue) The `dev` tier is a footgun: it is named for developers but gates at MSP_ADMIN. Any future doc tagged `audience: dev` will silently be MSP-visible. Consider renaming the tier or adding a startup assertion.
hiveiq added the Security
Priority
High
labels 2026-07-14 17:47:47 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: hiveiq-src/hiveops-guide#16