Files
PaperClipAI/doc
DottaandClaude Opus 4.8 1c5abf5c69 fix: close plugin issue-privacy bypasses on subtree/relations/interactions/documents
The prior enforce pass protected six plugin issue-read methods but left four
issue-derived read paths gated only on companyId, so a plugin with the read
capability and a known private issue ID could still exfiltrate private content
and relationship metadata (OWASP API BOLA / incomplete mediation):

- issues.getRelations returned relation summaries naming private targets
- issues.getSubtree returned private descendant rows plus their document
  summaries, relations, active-run and assignee metadata (and leaked a private
  root's existence)
- issues.listInteractions returned private interaction payloads
- issueDocuments.list/get returned private document bodies

Centralize the synthetic non-member check into shared helpers
(requirePluginReadableIssue, pluginReadableIssueIdsByIds,
pluginRedactRelationSummary) and route every issue-derived read through them
rather than maintaining a per-method allowlist:

- private direct roots are indistinguishable from missing ("Issue not found")
- getSubtree filters private descendants BEFORE fetching relations/documents/
  runs/assignees
- relation edges (getRelations, getSubtree, getOrchestrationSummary, and the
  summaries echoed by setBlockedBy/addBlockers/removeBlockers) drop unreadable
  targets, recursing into nested terminal blockers
- getOrchestrationSummary refactored onto the same helpers (no behavior change)

Add one old-code-failing regression test per bypass (private-root not-found,
open subtree with a private child + document, direct private document/
interaction reads, private blocker-edge redaction); keeps the eight existing
tests. Re-inventory documented in doc/ISSUE-PRIVACY.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-01 23:34:07 +00:00
..
2026-03-10 14:43:34 -05:00
2026-08-01 22:54:01 +00:00
2026-02-16 14:25:00 -06:00