CVE-2026-47417

HIGHPre-NVD 8.18.1
EchelonGraph scoreLOW confidence

This high-severity CVE scores 8.1 under the CNA's CVSS (NVD's own analysis pending). EPSS exploit probability: 0.0%, top 90% of all CVEs by exploit prediction. GitHub Security Advisory data not yet ingested — confidence will rise once GHSA publishes (typical lag: hours to days for open-source ecosystem CVEs; never for infrastructure-only CVEs).

Triggered by: NVD CVSS baseline
Sources: cna:github_m, epss
8.1
EchelonGraph verdictPlan a fixSerious severity, but no confirmed exploitation yet.
  • High severity, but no confirmed exploitation yet
CISA-KEV: Not listedEPSS: 0%CVSS: 8.1Exploit: NoneExposed: 0

No vendor fix yet — apply a workaround or compensating control (WAF / firewall / segmentation) and watch for a patch.

praisonai-platform: Comment endpoints accept any issue_id without workspace ownership check, cross-workspace comment read and post IDOR

Summary

Type: Insecure Direct Object Reference. The comment endpoints (POST /workspaces/{workspace_id}/issues/{issue_id}/comments and GET .../comments) gate access on require_workspace_member(workspace_id) only, then call CommentService.create(issue_id=issue_id, ...) and CommentService.list_for_issue(issue_id) without verifying that issue_id belongs to workspace_id. A user who is a member of any workspace W1 can read every comment on, and post new comments to, any issue in any other workspace W2. File: src/praisonai-platform/praisonai_platform/api/routes/issues.py, lines 143-171; src/praisonai-platform/praisonai_platform/services/comment_service.py, lines 19-53. Root cause: the route extracts workspace_id from the URL path and uses it solely for the membership gate, then passes the URL-supplied issue_id straight into CommentService without confirming that this issue exists in workspace_id. CommentService.list_for_issue(issue_id) runs SELECT * FROM comments WHERE issue_id = :issue_id with no workspace join. CommentService.create(issue_id=issue_id, ...) blindly writes a row with that issue_id. Both flows trust the URL-supplied issue ID as authoritative even though the membership check guarantees nothing about it.

Affected Code

File 1: src/praisonai-platform/praisonai_platform/api/routes/issues.py, lines 143-171.

@router.post("/{issue_id}/comments", response_model=CommentResponse, status_code=status.HTTP_201_CREATED)
async def add_comment(
    workspace_id: str,
    issue_id: str,
    body: CommentCreate,
    user: AuthIdentity = Depends(require_workspace_member),         # only checks attacker is in workspace_id
    session: AsyncSession = Depends(get_db),
):
    svc = CommentService(session)
    comment = await svc.create(
        issue_id=issue_id,                                          # <-- BUG: no validation that issue_id is in workspace_id
        author_id=user.id,
        content=body.content,
        author_type="member" if user.is_user else "agent",
        parent_id=body.parent_id,
    )
    return CommentResponse.model_validate(comment)

@router.get("/{issue_id}/comments", response_model=List[CommentResponse]) async def list_comments( workspace_id: str, issue_id: str, user: AuthIdentity = Depends(require_workspace_member), session: AsyncSession = Depends(get_db), ): svc = CommentService(session) comments = await svc.list_for_issue(issue_id) # <-- BUG: returns comments on any issue return [CommentResponse.model_validate(c) for c in comments]

File 2: src/praisonai-platform/praisonai_platform/services/comment_service.py, lines 19-53.

class CommentService:
    ...

async def create( self, issue_id: str, author_id: str, content: str, author_type: str = "member", comment_type: str = "comment", parent_id: Optional[str] = None, ) -> Comment: comment = Comment( issue_id=issue_id, # <-- accepts any issue_id; no workspace verify author_type=author_type, author_id=author_id, ... ) self._session.add(comment) await self._session.flush() return comment

async def list_for_issue(self, issue_id: str) -> list[Comment]: stmt = ( select(Comment) .where(Comment.issue_id == issue_id) # <-- no JOIN against issues for workspace constraint .order_by(Comment.created_at) ) result = await self._session.execute(stmt) return list(result.scalars().all())

Why it's wrong: the service trusts the caller-supplied issue_id as authoritative, but the route layer never verified that this issue belongs to the workspace the membership check covers. The standard FastAPI/SQLAlchemy fix is to first resolve the issue scoped to workspace_id (Issue.id = :issue_id AND Issue.workspace_id = :workspace_id) and only then proceed to comment operations. The MemberService.get(workspace_id, user_id) and LabelService.list_for_workspace(workspace_id) calls in the same codebase show the safe predicate; the comment service forgot to apply it.

Exploit Chain

  • Attacker registers a workspace W_attacker (member) and harvests a target issue UUID I_T from any side channel: agent prompts that mention issues, the activity feed (act_svc.log records issue_id), webhook payloads, exported issue dumps, or simply by being a low-privilege observer of the attacker's own workspace whose internals reference foreign issue IDs (cross-workspace links, search across activity events). State: attacker holds I_T.
  • Attacker authenticates and sends GET /workspaces/W_attacker/issues/I_T/comments. require_workspace_member(W_attacker, attacker) passes (attacker is a member of W_attacker). State: control flow enters list_comments with workspace_id=W_attacker, issue_id=I_T.
  • CommentService.list_for_issue(I_T) runs SELECT * FROM comments WHERE issue_id = 'I_T' with no workspace constraint. Every comment on the foreign issue is returned: content (often the most sensitive part of an issue tracker — bug-report repro steps with secrets, customer PII, internal triage notes), author_id, author_type, parent_id, created_at. State: response body is the full comment thread of the foreign issue.
  • Attacker repeats with POST /workspaces/W_attacker/issues/I_T/comments and a body of {"content": ""}. CommentService.create(issue_id=I_T, author_id=attacker, ...) writes a row with the foreign issue's id and the attacker's author_id. State: a new comment authored by the attacker appears in the foreign workspace's issue thread, indistinguishable to the foreign workspace's UI from a legitimate cross-workspace mention. Used at scale this becomes a comment-spam / phishing primitive (links in the comment body) targeting another tenant's users.
  • Final state: any attacker with one workspace-member token can exfiltrate every comment in the multi-tenant deployment given the issue UUIDs, and inject arbitrary comments under their own author identity into any foreign issue. The cross-workspace attribution gap is the worst part: the comment is recorded with the attacker's author_id, but the foreign workspace has no member with that id and the foreign workspace's audit logs show no event (the act_svc.log call in add_comment is omitted).

Security Impact

Severity: sec-high. CVSS 7.6: network attack, low complexity, low privileges, no user interaction, scope unchanged, high confidentiality (full comment threads), high integrity (cross-workspace comment injection under attacker's own id), no availability claim. Attacker capability: read every comment on every issue in the multi-tenant deployment given the issue UUIDs; post arbitrary comments under the attacker's identity into any foreign issue, allowing comment-spam, phishing-link injection into another tenant's UI, or social-engineering attribution attacks (the foreign workspace's UI renders a comment whose author belongs to no member of that workspace). Preconditions: praisonai-platform is deployed multi-tenant; the attacker has any membership token; the target issue's UUID is known or guessable. Differential: source-inspection-verified end-to-end. The asymmetry between CommentService.list_for_issue(issue_id) (no workspace predicate) and LabelService.list_for_workspace(workspace_id) (correctly workspace-scoped) confirms the gap. With the suggested fix below, every comment route first resolves the issue scoped to workspace_id, returns 404 if the issue is foreign, and only then proceeds.

Suggested Fix

Resolve the issue scoped to workspace_id at the route layer before dispatching to CommentService. This both fixes the read and the write paths and avoids changing the CommentService signature.

--- a/src/praisonai-platform/praisonai_platform/api/routes/issues.py
+++ b/src/praisonai-platform/praisonai_platform/api/routes/issues.py
@@ -141,6 +141,11 @@ async def delete_issue(...):
 # ── Comments ─────────────────────────────────────────────────────────────────

+async def _require_issue_in_workspace(session, workspace_id: str, issue_id: str): + issue = await IssueService(session).get(workspace_id, issue_id) # workspace-scoped get (see companion advisory) + if issue is None: + raise HTTPException(status_code=404, detail="Issue not found") + @router.post("/{issue_id}/comments", response_model=CommentResponse, status_code=status.HTTP_201_CREATED) async def add_comment( workspace_id: str, @@ -149,6 +154,7 @@ async def add_comment( user: AuthIdentity = Depends(require_workspace_member), session: AsyncSession = Depends(get_db), ): + await _require_issue_in_workspace(session, workspace_id, issue_id) svc = CommentService(session) comment = await svc.create( issue_id=issue_id, @@ -167,5 +173,6 @@ async def list_comments( user: AuthIdentity = Depends(require_workspace_member), session: AsyncSession = Depends(get_db), ): + await _require_issue_in_workspace(session, workspace_id, issue_id) svc = CommentService(session) comments = await svc.list_for_issue(issue_id)

Companion advisories file the same workspace-scoping gap for AgentService, IssueService, ProjectService, and LabelService. Each is a separate exploitable IDOR.

CVSS v3
8.1
EG Score
8.1(low)
EPSS
9.7%
KEV
Not listed

Published

June 1, 2026

Last Modified

June 1, 2026

Vendor Advisories for CVE-2026-47417(1)

These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

Affected Packages

(1 across 1 ecosystem)
PyPI(1)
PackageVulnerable rangeFixed inDependents
praisonai-platform0.1.0, 0.1.1, 0.1.2, 0.1.30.1.4

Data Freshness Timeline

(refreshed 4× in last 7d / 39× in last 30d)

Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

  1. 2026-07-02 15:46 UTCEG score recompute
  2. 2026-07-02 02:25 UTCEG score recompute
  3. 2026-07-01 13:31 UTCEG score recompute
  4. 2026-07-01 00:39 UTCEG score recompute
  5. 2026-06-30 00:41 UTCEG score recompute
  6. 2026-06-29 11:50 UTCEG score recompute
  7. 2026-06-28 22:15 UTCEG score recompute
  8. 2026-06-28 09:21 UTCEG score recompute
  9. 2026-06-27 20:29 UTCEG score recompute
  10. 2026-06-27 07:37 UTCEG score recompute
  11. 2026-06-26 18:46 UTCEG score recompute
  12. 2026-06-26 05:42 UTCEG score recompute
  13. 2026-06-25 16:50 UTCEG score recompute
  14. 2026-06-25 03:57 UTCEG score recompute
  15. 2026-06-24 15:00 UTCEG score recompute
  16. 2026-06-24 02:07 UTCEG score recompute
  17. 2026-06-18 22:48 UTCEG score recompute
  18. 2026-06-18 09:56 UTCEG score recompute
  19. 2026-06-17 17:34 UTCEG score recompute
  20. 2026-06-17 03:50 UTCEG score recompute
  21. 2026-06-16 14:57 UTCEG score recompute
  22. 2026-06-16 02:04 UTCEG score recompute
  23. 2026-06-15 13:12 UTCEG score recompute
  24. 2026-06-15 00:18 UTCEG score recompute
  25. 2026-06-14 23:18 UTCEPSS rescore
Show 26 more
  1. 2026-06-14 11:27 UTCEG score recompute
  2. 2026-06-13 22:35 UTCEG score recompute
  3. 2026-06-13 09:44 UTCEG score recompute
  4. 2026-06-12 23:12 UTCEPSS rescore
  5. 2026-06-12 20:52 UTCEG score recompute
  6. 2026-06-12 08:01 UTCEG score recompute
  7. 2026-06-11 19:10 UTCEG score recompute
  8. 2026-06-11 06:18 UTCEG score recompute
  9. 2026-06-10 17:26 UTCEG score recompute
  10. 2026-06-10 04:35 UTCEG score recompute
  11. 2026-06-09 15:44 UTCEG score recompute
  12. 2026-06-09 02:53 UTCEG score recompute
  13. 2026-06-08 14:01 UTCEG score recompute
  14. 2026-06-08 01:09 UTCEG score recompute
  15. 2026-06-07 12:18 UTCEG score recompute
  16. 2026-06-06 23:27 UTCEG score recompute
  17. 2026-06-06 10:35 UTCEG score recompute
  18. 2026-06-05 21:44 UTCEG score recompute
  19. 2026-06-05 08:53 UTCEG score recompute
  20. 2026-06-04 20:01 UTCEG score recompute
  21. 2026-06-04 07:09 UTCEG score recompute
  22. 2026-06-03 18:17 UTCEG score recompute
  23. 2026-06-03 05:25 UTCEG score recompute
  24. 2026-06-02 16:33 UTCEG score recompute
  25. 2026-06-02 03:41 UTCEG score recompute
  26. 2026-06-01 14:49 UTCEG score recompute

Frequently asked(5)

What is CVE-2026-47417?
CVE-2026-47417 is a high vulnerability published on June 1, 2026. praisonai-platform: Comment endpoints accept any issue_id without workspace ownership check, cross-workspace comment read and post IDOR Summary Type: Insecure Direct Object Reference. The comment endpoints (POST /workspaces/{workspaceid}/issues/{issueid}/comments and GET .../comments) gate access…
When was CVE-2026-47417 disclosed?
CVE-2026-47417 was first published in the National Vulnerability Database on June 1, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
Is CVE-2026-47417 actively exploited?
CVE-2026-47417 is not currently on CISA's Known Exploited Vulnerabilities catalog. FIRST EPSS estimates a 9.7% percentile likelihood of exploitation in the next 30 days — higher percentiles indicate greater predicted risk.
What is the CVSS score of CVE-2026-47417?
CVE-2026-47417 has a CVSS v4.0 base score of 8.1 (CNA self-assessment; NVD's own analysis pending). The EG score is currently aggregating — additional source signals are being incorporated as they become available..
How do I remediate CVE-2026-47417?
Patch to the fixed version published by the affected vendor. Where vendor advisories exist for CVE-2026-47417, EchelonGraph cross-links them in the Vendor Advisories panel below — those typically contain the canonical remediation steps, fixed version numbers, and any vendor-specific mitigations.

Dependency Blast Radius

See which npm, PyPI, Go, and Maven packages are affected by CVE-2026-47417

Explore →

Is Your Infrastructure Affected by CVE-2026-47417?

EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.